diff --git a/.gitignore b/.gitignore
index 015e42057..c070f3a43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
 node_modules/
 /.idea/
-dist
 demo.js
 demo.css
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
index 8b8c96483..5824052d0 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -51,6 +51,14 @@ module.exports = function (grunt) {
                 ],
                 dest: 'dist/case.js'
             },
+            widgetJs: {
+                src: [
+                    'src/widget/paramsettingcombo/popup.param.js',
+                    'src/widget/sequencetable/treenumber.sequencetable.js',
+                    'src/widget/**/*.js'
+                ],
+                dest: "dist/widget.js"
+            },
             coreCss: {
                 src: ['src/css/core/**/*.css', 'src/css/utils/**/*.css'],
                 dest: 'dist/core.css'
@@ -59,9 +67,13 @@ module.exports = function (grunt) {
                 src: ['src/css/base/**/*.css'],
                 dest: 'dist/base.css'
             },
+            widgetCss: {
+                src: ['src/css/widget/**/*.css'],
+                dest: 'dist/widget.css'
+            },
 
             demoJs: {
-                src: ['demo/version.js', 'demo/app.js', 'demo/js/**/*.js'],
+                src: ['demo/version.js', 'demo/app.js', 'demo/config.js', 'demo/js/**/*.js'],
                 dest: 'demo/dist/demo.js'
             },
             demoCss: {
diff --git a/demo.html b/demo.html
index 52ce5e093..20808e0f0 100644
--- a/demo.html
+++ b/demo.html
@@ -14,6 +14,7 @@
     <script src="./dist/core.js"></script>
     <script src="./dist/base.js"></script>
     <script src="./dist/case.js"></script>
+    <script src="./dist/widget.js"></script>
     <script src="demo/dist/demo.js"></script>
 </head>
 <body>
diff --git a/demo/config.js b/demo/config.js
new file mode 100644
index 000000000..76aeb0eee
--- /dev/null
+++ b/demo/config.js
@@ -0,0 +1,937 @@
+/**
+ * Created by User on 2017/3/21.
+ */
+FINEUI = {};
+FINEUI.WIDGET = [{
+    id: -1,
+    text: "文本框",
+    isParent: true,
+    open: false
+}, {
+    id: 2,
+    pId: -1,
+    text: "文本框",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 1,
+    text: "树",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 7,
+    text: "表格",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 8,
+    text: "图表",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 3,
+    text: "日历",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 4,
+    text: "分页相关",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 5,
+    text: "tip提示",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 6,
+    text: "组合控件",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 9,
+    text: "选色控件",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 10,
+    text: "canvas绘图",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    id: 11,
+    text: "svg绘图",
+    isParent: true,
+    open: false
+}, {
+    pId: -1,
+    text: "bi.message",
+    type: "message"
+}, {
+    pId: -1,
+    text: "bi.button",
+    type: "button"
+}, {
+    pId: -1,
+    text: "bi.multifile",
+    type: "multifile"
+}, {
+    pId: -1,
+    text: "bi.label",
+    type: "label"
+}, {
+    pId: 2,
+    text: "bi.editor",
+    type: "editor"
+}, {
+    pId: 2,
+    text: "bi.state_editor",
+    type: "state_editor"
+}, {
+    pId: 2,
+    text: "bi.record_editor",
+    type: "record_editor"
+}, {
+    pId: 2,
+    text: "bi.sign_editor",
+    type: "sign_editor"
+}, {
+    pId: 2,
+    text: "bi.shelter_editor",
+    type: "shelter_editor"
+}, {
+    pId: 2,
+    text: "bi.code_editor",
+    type: "code_editor"
+}, {
+    pId: 2,
+    text: "bi.textareaeditor",
+    type: "textareaeditor"
+}, {
+    pId: 6,
+    text: "bi.combo",
+    type: "combo"
+}, {
+    pId: 6,
+    text: "bi.combo(各种位置)",
+    type: "combo2"
+}, {
+    pId: 6,
+    text: "bi.expander",
+    type: "expander"
+}, {
+    pId: 6,
+    text: "bi.switcher",
+    type: "switcher"
+}, {
+    pId: 6,
+    text: "bi.searcher",
+    type: "searcher"
+}, {
+    pId: 6,
+    text: "bi.bubble_combo",
+    type: "bubble_combo"
+}, {
+    pId: 1,
+    text: "bi.customtree",
+    type: "customtree"
+}, {
+    pId: 1,
+    text: "bi.tree",
+    type: "tree"
+}, {
+    pId: 1,
+    text: "bi.sync_tree",
+    type: "synctree"
+}, {
+    pId: 1,
+    text: "bi.part_tree",
+    type: "parttree"
+}, {
+    pId: 1,
+    text: "bi.display_tree",
+    type: "displaytree"
+}, {
+    pId: 1,
+    text: "bi.simple_tree",
+    type: "simpletree"
+}, {
+    pId: 1,
+    text: "bi.level_tree",
+    type: "leveltree"
+}, {
+    pId: 1,
+    text: "bi.branch_tree",
+    type: "branch_tree"
+}, {
+    pId: 1,
+    text: "bi.handstand_branch_tree",
+    type: "handstand_branch_tree"
+}, {
+    pId: 2,
+    text: "bi.formula",
+    type: "formula"
+}, {
+    pId: 9,
+    text: "bi.farbtastic",
+    type: "farbtastic"
+}, {
+    pId: 9,
+    text: "bi.color_picker",
+    type: "color_picker"
+}, {
+    pId: 9,
+    text: "bi.color_picker_editor",
+    type: "color_picker_editor"
+}, {
+    pId: 7,
+    text: "bi.table_view",
+    type: "table_view"
+}, {
+    pId: 7,
+    text: "bi.table_tree",
+    type: "tabletree"
+}, {
+    pId: 7,
+    text: "bi.layer_tree_table",
+    type: "layer_tree_table"
+}, {
+    pId: 7,
+    text: "bi.tabler",
+    type: "tabler"
+}, {
+    pId: 8,
+    text: "bi.chart",
+    type: "chart"
+}, {
+    pId: 8,
+    text: "charts",
+    type: "charts"
+}, {
+    pId: 5,
+    text: "bi.bubble",
+    type: "bubble"
+}, {
+    pId: 5,
+    text: "bi.toast",
+    type: "toast"
+}, {
+    pId: 5,
+    text: "bi.tooltip",
+    type: "tooltip"
+}, {
+    pId: 4,
+    text: "bi.tab",
+    type: "tab"
+}, {
+    pId: 4,
+    text: "bi.pager",
+    type: "pager"
+}, {
+    pId: 4,
+    text: "bi.loader",
+    type: "loader"
+}, {
+    pId: 4,
+    text: "bi.navigation",
+    type: "navigation"
+}, {
+    pId: 4,
+    text: "bi.scroll_view",
+    type: "scrollview"
+}, {
+    pId: 4,
+    text: "bi.number_pager",
+    type: "numberpager"
+}, {
+    pId: 4,
+    text: "bi.direction_pager",
+    type: "directionpager"
+}, {
+    pId: 4,
+    text: "bi.skip_pager",
+    type: "skippager"
+}, {
+    pId: 4,
+    text: "bi.all_pager",
+    type: "allpager"
+}, {
+    pId: 4,
+    text: "bi.lazyloader",
+    type: "lazy_loader"
+}, {
+    pId: 3,
+    text: "bi.calendar",
+    type: "calendar"
+}, {
+    pId: 3,
+    text: "bi.year_calendar",
+    type: "year_calendar"
+}, {
+    pId: 10,
+    text: "bi.canvas",
+    type: "canvas"
+}, {
+    pId: 10,
+    text: "bi.complex_canvas",
+    type: "complex_canvas"
+}, {
+    pId: 11,
+    text: "bi.svg",
+    type: "svg"
+}, {
+    text: "bi.zero_clip",
+    type: "zclip"
+}, {
+    text: "bi.grid_view",
+    type: "gridview"
+}, {
+    text: "bi.collection_view",
+    type: "collectionview"
+}, {
+    text: "bi.grid_table",
+    type: "gridtable"
+}];
+_Models.layout = [{
+    text: "bi.center_adapt",
+    type: "center_adapt"
+}, {
+    text: "bi.float_center_adapt",
+    type: "float_center_adapt"
+}, {
+    text: "bi.absolute_center_adapt",
+    type: "absolute_center_adapt"
+}, {
+    text: "bi.flex_center",
+    type: "flex_center"
+}, {
+    text: "bi.inline_center_adapt",
+    type: "inline_center_adapt"
+}, {
+    text: "bi.vertical_adapt",
+    type: "vertical_adapt"
+}, {
+    text: "bi.inline_vertical_adapt",
+    type: "inline_vertical_adapt"
+}, {
+    text: "bi.horizontal_adapt",
+    type: "horizontal_adapt"
+}, {
+    text: "bi.horizontal_auto",
+    type: "horizontal_auto"
+}, {
+    text: "bi.horizontal_float",
+    type: "horizontal_float"
+}, {
+    text: "bi.left_right_vertical_adapt",
+    type: "left_right_vertical_adapt"
+}, {
+    text: "bi.center",
+    type: "center"
+}, {
+    text: "bi.float_center",
+    type: "float_center"
+}, {
+    text: "bi.vertical",
+    type: "vertical"
+}, {
+    text: "bi.horizontal",
+    type: "horizontal"
+}, {
+    text: "bi.border",
+    type: "border"
+}, {
+    text: "bi.card",
+    type: "card"
+}, {
+    text: "bi.left, bi.right",
+    type: "flow"
+}, {
+    text: "bi.lattice",
+    type: "lattice"
+}, {
+    text: "bi.inline",
+    type: "inline"
+}, {
+    text: "bi.htape",
+    type: "htape"
+}, {
+    text: "bi.vtape",
+    type: "vtape"
+}, {
+    text: "bi.grid",
+    type: "grid"
+}, {
+    text: "bi.table",
+    type: "table"
+}, {
+    text: "bi.division",
+    type: "division"
+}, {
+    text: "bi.window",
+    type: "window"
+}, {
+    text: "bi.td",
+    type: "td"
+}];
+FINEUI.DETAIL = [{
+    id: -2,
+    text: "各种基础小控件"
+},{
+    pId: -2,
+    id: -1,
+    text: "各种基础小控件"
+}, {
+    pId: -2,
+    id: 1,
+    text: "文本框控件"
+}, {
+    pId: -2,
+    id: 12,
+    text: "下拉框控件(可测)"
+}, {
+    pId: -2,
+    id: 2,
+    text: "年份控件(可测)"
+}, {
+    pId: -2,
+    id: 3,
+    text: "月份控件(可测)"
+}, {
+    pId: -2,
+    id: 4,
+    text: "季度控件(可测)"
+}, {
+    pId: -2,
+    id: 5,
+    text: "简单日期控件(不参与测试)"
+}, {
+    pId: -2,
+    id: 6,
+    text: "复杂日期控件(可测)"
+}, {
+    pId: -2,
+    id: 7,
+    text: "下拉列表(可测)"
+}, {
+    pId: -2,
+    id: 8,
+    text: "选择字段列表(可测)"
+}, {
+    pId: -2,
+    id: 9,
+    text: "公式编辑器(可测)"
+}, {
+    id: 10,
+    pId: -2,
+    text: "数值区间控件(可测)"
+}, {
+    id: 11,
+    pId: -2,
+    text: "下拉复选框有确定按钮(已阅)"
+}, {
+    id: 13,
+    pId: -2,
+    text: "移动和复制到分组(可测)"
+}, {
+    id: 14,
+    pId: -2,
+    text: "单选下拉树(可测)"
+}, {
+    id: 23,
+    pId: -2,
+    text: "可选下拉树(可测)"
+}, {
+    id: 15,
+    pId: -2,
+    text: "提示对话框(可测)"
+}, {
+    id: 16,
+    pId: -2,
+    text: "复选下拉树(已阅)"
+}, {
+    pId: -2,
+    id: 17,
+    text: "时间区间控件"
+}, {
+    pId: -2,
+    id: 30,
+    text: "简单搜索控件"
+}, {
+    pId: -2,
+    id: 18,
+    text: "简单选择字段"
+}, {
+    pId: -2,
+    id: 19,
+    text: "过滤结构"
+}, {
+    pId: -2,
+    id: 20,
+    text: "选色控件"
+}, {
+    pId: -2,
+    id: 21,
+    text: "文本控件"
+}, {
+    pId: -2,
+    id: 22,
+    text: "路径选择"
+}, {
+    pId: -2,
+    id: 24,
+    text: "文件管理"
+}, {
+    pId: -2,
+    id: 25,
+    text: "表关联树"
+}, {
+    pId: -2,
+    id: 26,
+    text: "关联视图"
+}, {
+    pId: -2,
+    id: 27,
+    text: "表格"
+}, {
+    pId: -2,
+    id: 32,
+    text: "序号表格"
+}, {
+    pId: -2,
+    id: 28,
+    text: "图片组件&web组件"
+}, {
+    pId: -2,
+    id: 29,
+    text: "布局"
+}, {
+    pId: -2,
+    id: 31,
+    text: "详细图表"
+}, {
+    pId: -2,
+    id: 33,
+    text: "树标签"
+}, {
+    pId: -2,
+    id: 34,
+    text: "单值滑块"
+}, {
+    pId: -2,
+    id: 35,
+    text: "区间滑块"
+}, {
+    pId: -2,
+    id: 36,
+    text: "文本列表"
+}, {
+    pId: -2,
+    id: 37,
+    text: "树列表"
+}, {
+    pId: -2,
+    id: 38,
+    text: "日期面板"
+}, {
+    pId: -2,
+    id: 39,
+    text: "螺旋分析tab控件"
+}, {
+    pId: -2,
+    id: 40,
+    text: "数值微调器"
+},
+
+
+    {
+        pId: -1,
+        text: "各种通用按钮",
+        type: "buttons"
+    }, {
+        pId: -1,
+        text: "各种提示性信息",
+        type: "tips"
+    }, {
+        pId: -1,
+        text: "各种items",
+        type: "items"
+    }, {
+        pId: -1,
+        text: "各种节点node",
+        type: "nodes"
+    }, {
+        pId: -1,
+        text: "各种segment",
+        type: "segments"
+    }, {
+        pId: -1,
+        text: "各种面板",
+        type: "panes"
+    }, {
+        pId: -1,
+        text: "bi.loading_mask",
+        type: "loadingmask"
+    }, {
+        pId: -1,
+        text: "可以切换的树",
+        type: "switch_tree"
+    }, {
+        pId: -1,
+        text: "进度条",
+        type: "progressbar"
+    }, {
+        pId: 1,
+        text: "bi.text_editor",
+        type: "text_editor"
+    }, {
+        pId: 1,
+        text: "bi.search_editor",
+        type: "search_editor"
+    }, {
+        pId: 1,
+        text: "bi.adapt_editor",
+        type: "adapt_editor"
+    }, {
+        pId: 1,
+        text: "bi.sign_initial_editor",
+        type: "sign_initial_editor"
+    }, {
+        pId: 1,
+        text: "bi.sign_style_editor",
+        type: "sign_style_editor"
+    }, {
+        pId: 2,
+        text: "bi.year_combo",
+        type: "year_combo"
+    }, {
+        pId: 3,
+        text: "bi.month_combo",
+        type: "month_combo"
+    }, {
+        pId: 4,
+        text: "bi.quarter_combo",
+        type: "quarter_combo"
+    }, {
+        pId: 5,
+        text: "bi.date_combo",
+        type: "date_combo"
+    }, {
+        pId: 7,
+        text: "bi.down_list_combo",
+        type: "down_list_combo"
+    }, {
+        pId: 12,
+        text: "各种trigger",
+        type: "triggers"
+    }, {
+        pId: 12,
+        text: "bi.text_type_combo",
+        type: "text_icon_combo"
+    }, {
+        pId: 12,
+        text: "bi.static_combo",
+        type: "single_select_combo"
+    }, {
+        pId: 12,
+        text: "bi.text_type_down_list_combo",
+        type: "text_icon_down_list_combo"
+    }, {
+        pId: 12,
+        text: "bi.param_date_combo",
+        type: "param_date_combo"
+    }, {
+        pId: 12,
+        text: "bi.icon_combo",
+        type: "icon_combo"
+    }, {
+        pId: 12,
+        text: "bi.formula_combo",
+        type: "formula_combo"
+    }, {
+        pId: 9,
+        text: "bi.formula_insert",
+        type: "formula_insert"
+    }, {
+        pId: 9,
+        text: "bi.formula_pane",
+        type: "formula_pane"
+    }, {
+        pId: 8,
+        text: "bi.select_data_tree",
+        type: "select_data_tree"
+    }, {
+        pId: 8,
+        text: "bi.select_data_switcher",
+        type: "select_data_switcher"
+    }, {
+        pId: 8,
+        text: "bi.select_data_search_result",
+        type: "select_data_search_result"
+    }, {
+        pId: 8,
+        text: "bi.select_data_searcher(点这)",
+        type: "select_data_searcher"
+    }, {
+        pId: 6,
+        text: "bi.multidate_combo",
+        type: "multidate_combo"
+    }, {
+        pId: 17,
+        text: "bi.time_interval",
+        type: "time_interval"
+    }, {
+        pId: 10,
+        text: "bi.numerical_interval",
+        type: "numerical_interval"
+    }, {
+        pId: 11,
+        text: "bi.multi_select_trigger",
+        type: "multi_select_trigger"
+    }, {
+        pId: 11,
+        text: "bi.multi_select_search_pane",
+        type: "multi_select_search_pane"
+    }, {
+        pId: 11,
+        text: "bi.multi_select_popup_view",
+        type: "multi_select_popup_view"
+    }, {
+        pId: 11,
+        text: "bi.multi_select_check_pane",
+        type: "multi_select_check_pane"
+    }, {
+        pId: 11,
+        text: "bi.multi_select_combo",
+        type: "multi_select_combo"
+    }, {
+        pId: 13,
+        text: "bi.move2group_combo",
+        type: "move2group_combo"
+    }, {
+        pId: 13,
+        text: "bi.copy2group_combo",
+        type: "copy2group_combo"
+    }, {
+        pId: 14,
+        text: "bi.single_tree_combo",
+        type: "single_tree_combo"
+    }, {
+        pId: 14,
+        text: "bi.multilayer_single_tree_combo",
+        type: "multilayer_single_tree_combo"
+    }, {
+        pId: 23,
+        text: "bi.select_tree_combo",
+        type: "select_tree_combo"
+    }, {
+        pId: 23,
+        text: "bi.multilayer_select_tree_combo",
+        type: "multilayer_select_tree_combo"
+    }, {
+        pId: 15,
+        text: "bi.dialog",
+        type: "dialog"
+    }, {
+        pId: 16,
+        text: "bi.multi_tree",
+        type: "multi_tree"
+    }, {
+        pId: 18,
+        text: "bi.simple_select_data_searcher",
+        type: "simple_select_data_searcher"
+    }, {
+        pId: 19,
+        text: "bi.filter_pane",
+        type: "filter_pane"
+    }, {
+        pId: 19,
+        text: "bi.filter_operation",
+        type: "filter_operation"
+    }, {
+        pId: 19,
+        text: "bi.filter",
+        type: "filter"
+    }, {
+        pId: 20,
+        text: "bi.color_chooser",
+        type: "color_chooser"
+    }, {
+        pId: 21,
+        text: "bi.text_toolbar",
+        type: "text_toolbar"
+    }, {
+        pId: 21,
+        text: "bi.text_area",
+        type: "text_area"
+    }, {
+        pId: 22,
+        text: "bi.path_chooser",
+        type: "path_chooser"
+    }, {
+        pId: 22,
+        text: "bi.direction_path_chooser",
+        type: "direction_path_chooser"
+    }, {
+        pId: 24,
+        text: "bi.file_manager",
+        type: "file_manager"
+    }, {
+        pId: 25,
+        text: "bi.branch_relation",
+        type: "branch_relation"
+    }, {
+        pId: 26,
+        text: "bi.relation_view",
+        type: "relation_view"
+    }, {
+        pId: 27,
+        text: "bi.preview_table",
+        type: "preview_table"
+    }, {
+        pId: 27,
+        text: "bi.adaptive_table",
+        type: "adaptive_table"
+    }, {
+        pId: 27,
+        text: "bi.adaptive_table(冻结表头)",
+        type: "adaptive_table2"
+    }, {
+        pId: 27,
+        text: "bi.custom_scroll_table",
+        type: "custom_scroll_table"
+    }, {
+        pId: 27,
+        text: "bi.page_table",
+        type: "page_table"
+    }, {
+        pId: 27,
+        text: "bi.page_table(冻结)",
+        type: "page_table2"
+    }, {
+        pId: 27,
+        text: "bi.page_table(调整列宽)",
+        type: "page_table3"
+    }, {
+        pId: 27,
+        text: "bi.excel_table",
+        type: "excel_table"
+    }, {
+        pId: 27,
+        text: "bi.sortable_table",
+        type: "sortable_table"
+    }, {
+        pId: 27,
+        text: "bi.excel_view_display_manager",
+        type: "excel_view_display_manager"
+    }, {
+        pId: 32,
+        text: "bi.sequence_table",
+        type: "sequence_table"
+    }, {
+        pId: 32,
+        text: "bi.sequence_table(带有汇总)",
+        type: "sequence_table2"
+    }, {
+        pId: 28,
+        text: "bi.upload_image",
+        type: "upload_image"
+    }, {
+        pId: 28,
+        text: "bi.web_page",
+        type: "web_page"
+    }, {
+        pId: 29,
+        text: "bi.arrangement_droppable",
+        type: "arrangement_droppable"
+    }, {
+        pId: 29,
+        text: "bi.arrangement",
+        type: "arrangement"
+    }, {
+        pId: 29,
+        text: "bi.adaptive_arrangement",
+        type: "adaptive_arrangement"
+    }, {
+        pId: 29,
+        text: "bi.arrangement(网格布局)",
+        type: "grid_arrangement"
+    }, {
+        pId: 29,
+        text: "bi.adaptive_arrangement(网格布局)",
+        type: "grid_adaptive_arrangement"
+    }, {
+        pId: 30,
+        text: "bi.simple_searcher",
+        type: "simple_searcher"
+    }, {
+        pId: 31,
+        text: "选色",
+        type: "select_color_combo"
+    }, {
+        pId: 31,
+        text: "bi.detail_chart",
+        type: "detail_chart"
+    }, {
+        pId: 31,
+        text: "柱形",
+        type: "column_charts"
+    }, {
+        pId: 31,
+        text: "条形图",
+        type: "bar_charts"
+    }, {
+        pId: 31,
+        text: "面积图",
+        type: "area_charts"
+    }, {
+        pId: 31,
+        text: "其他",
+        type: "other_charts"
+    }, {
+        pId: 33,
+        text: "文本标签",
+        type: "list_label"
+    }, {
+        pId: 33,
+        text: "树标签",
+        type: "tree_label"
+    }, {
+        pId: 34,
+        text: "滑块",
+        type: "slider"
+    }, {
+        pId: 35,
+        text: "区间双滑块",
+        type: "interval_slider"
+    }, {
+        pId: 36,
+        text: "文本列表",
+        type: "string_list"
+    }, {
+        pId: 37,
+        text: "树列表",
+        type: "tree_list"
+    }, {
+        pId: 38,
+        text: "日期面板",
+        type: "data_pane"
+    }, {
+        pId: 39,
+        text: "螺旋分析tab控件",
+        type: "dynamic_group_tab"
+    }, {
+        pId: 40,
+        text: "数值微调器",
+        type: "finetuning_number_editor"
+    }];
\ No newline at end of file
diff --git a/demo/css/west.css b/demo/css/west.css
index 4601cc494..3fa43c065 100644
--- a/demo/css/west.css
+++ b/demo/css/west.css
@@ -1,3 +1,3 @@
 .demo-west {
-  background-color: #222d32;
+  background-color: #7f7f7f;
 }
diff --git a/demo/js/west.js b/demo/js/west.js
index aaa8740d0..7efe65ccf 100644
--- a/demo/js/west.js
+++ b/demo/js/west.js
@@ -3,7 +3,13 @@ Demo.West = BI.inherit(BI.Widget, {
         baseCls: "demo-west"
     },
     render: function () {
-
+        return {
+            type: "bi.vertical",
+            items: [{
+                type: "bi.vertical",
+                items: []
+            }]
+        }
     }
 });
 $.shortcut("demo.west", Demo.West);
\ No newline at end of file
diff --git a/demo/less/west.less b/demo/less/west.less
index c3aabe177..8fc638f67 100644
--- a/demo/less/west.less
+++ b/demo/less/west.less
@@ -1,3 +1,3 @@
 .demo-west {
-  background-color: #222d32;
+  background-color: #7f7f7f;
 }
\ No newline at end of file
diff --git a/dist/base.css b/dist/base.css
new file mode 100644
index 000000000..6505eea15
--- /dev/null
+++ b/dist/base.css
@@ -0,0 +1,3690 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-picker-button {
+  background-color: #eaeaea;
+}
+.bi-color-picker-button .color-picker-button-mask {
+  border: 1px solid #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-picker > .center-element {
+  border-left: 1px solid #ffffff;
+  border-top: 1px solid #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-picker-editor .color-picker-editor-label {
+  color: #808080;
+}
+.bi-color-picker-editor .color-picker-editor-display {
+  background: #ffffff;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -webkit-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -moz-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/* BASICS */
+.CodeMirror {
+  /* Set height, width, borders, and global font properties here */
+  font-family: monospace;
+  cursor: text;
+  width: 100%;
+  height: 100%;
+  color: black;
+}
+/* PADDING */
+.CodeMirror-lines {
+  padding: 4px 0;
+  /* Vertical padding around content */
+}
+.CodeMirror pre {
+  padding: 0 4px;
+  /* Horizontal padding of content */
+}
+.CodeMirror-scrollbar-filler,
+.CodeMirror-gutter-filler {
+  background-color: white;
+  /* The little square between H and V scrollbars */
+}
+/* GUTTER */
+.CodeMirror-gutters {
+  border-right: 1px solid #ddd;
+  background-color: #f7f7f7;
+  white-space: nowrap;
+}
+.CodeMirror-linenumber {
+  padding: 0 3px 0 5px;
+  min-width: 20px;
+  text-align: right;
+  color: #999;
+  white-space: nowrap;
+}
+.CodeMirror-guttermarker {
+  color: black;
+}
+.CodeMirror-guttermarker-subtle {
+  color: #999;
+}
+/* CURSOR */
+.CodeMirror div.CodeMirror-cursor {
+  border-left: 1px solid black;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: #7e7;
+}
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+}
+@-moz-keyframes blink {
+  0% {
+    background: #7e7;
+  }
+  50% {
+    background: none;
+  }
+  100% {
+    background: #7e7;
+  }
+}
+@-webkit-keyframes blink {
+  0% {
+    background: #7e7;
+  }
+  50% {
+    background: none;
+  }
+  100% {
+    background: #7e7;
+  }
+}
+@keyframes blink {
+  0% {
+    background: #7e7;
+  }
+  50% {
+    background: none;
+  }
+  100% {
+    background: #7e7;
+  }
+}
+/* Can style cursor different in overwrite (non-insert) mode */
+.cm-tab {
+  display: inline-block;
+  text-decoration: inherit;
+}
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  position: absolute;
+}
+/* DEFAULT THEME */
+.cm-s-default .cm-header {
+  color: blue;
+}
+.cm-s-default .cm-quote {
+  color: #090;
+}
+.cm-negative {
+  color: #d44;
+}
+.cm-positive {
+  color: #292;
+}
+.cm-header,
+.cm-strong {
+  font-weight: bold;
+}
+.cm-em {
+  font-style: italic;
+}
+.cm-link {
+  text-decoration: underline;
+}
+.cm-strikethrough {
+  text-decoration: line-through;
+}
+.cm-s-default .cm-atom {
+  color: #219;
+}
+.cm-s-default .cm-number {
+  color: #164;
+}
+.cm-s-default .cm-def {
+  color: #00f;
+}
+.cm-s-default .cm-variable-2 {
+  color: #05a;
+}
+.cm-s-default .cm-variable-3 {
+  color: #085;
+}
+.cm-s-default .cm-comment {
+  color: #a50;
+}
+.cm-s-default .cm-string {
+  color: #a11;
+}
+.cm-s-default .cm-string-2 {
+  color: #f50;
+}
+.cm-s-default .cm-meta {
+  color: #555;
+}
+.cm-s-default .cm-qualifier {
+  color: #555;
+}
+.cm-s-default .cm-builtin {
+  color: #30a;
+}
+.cm-s-default .cm-bracket {
+  color: #997;
+}
+.cm-s-default .cm-tag {
+  color: #170;
+}
+.cm-s-default .cm-attribute {
+  color: #00c;
+}
+.cm-s-default .cm-hr {
+  color: #999;
+}
+.cm-s-default .cm-link {
+  color: #00c;
+}
+.cm-s-default span[class*="fieldName"] {
+  color: white;
+  padding: 1px ;
+  margin: 1px 0px;
+  background: #009de3;
+}
+.cm-s-default span[class*="start"] {
+  -webkit-border-radius: 3px 0px 0px 3px;
+  -moz-border-radius: 3px 0px 0px 3px;
+  border-radius: 3px 0px 0px 3px;
+  margin-left: 3px;
+}
+.cm-s-default span[class*="end"] {
+  -webkit-border-radius: 0px 3px 3px 0px;
+  -moz-border-radius: 0px 3px 3px 0px;
+  border-radius: 0px 3px 3px 0px;
+  margin-right: 3px;
+}
+.cm-s-default span[class*="start end"] {
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+.cm-s-default span[class*="#"] {
+  color: #009de3;
+}
+.cm-s-default .cm-error {
+  color: #f00;
+}
+.cm-invalidchar {
+  color: #f00;
+}
+.CodeMirror-composing {
+  border-bottom: 2px solid;
+}
+/* Default styles for common addons */
+div.CodeMirror span.CodeMirror-matchingbracket {
+  color: #0f0;
+}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {
+  color: #f22;
+}
+.CodeMirror-matchingtag {
+  background: rgba(255, 150, 0, 0.3);
+}
+.CodeMirror-activeline-background {
+  background: #e8f2ff;
+}
+/* STOP */
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+.CodeMirror {
+  position: relative;
+  overflow: hidden;
+  background: white;
+}
+.CodeMirror-scroll {
+  overflow: scroll !important;
+  /* Things will break if this is overridden */
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px;
+  margin-right: -30px;
+  padding-bottom: 30px;
+  height: 100%;
+  outline: none;
+  /* Prevent dragging from highlighting the element */
+  position: relative;
+}
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+}
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actuall scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar,
+.CodeMirror-hscrollbar,
+.CodeMirror-scrollbar-filler,
+.CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+.CodeMirror-vscrollbar {
+  right: 0;
+  top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+  bottom: 0;
+  left: 0;
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+  right: 0;
+  bottom: 0;
+}
+.CodeMirror-gutter-filler {
+  left: 0;
+  bottom: 0;
+}
+.CodeMirror-gutters {
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: 3;
+}
+.CodeMirror-gutter {
+  white-space: normal;
+  height: 100%;
+  display: inline-block;
+  margin-bottom: -30px;
+  /* Hack to make IE7 behave */
+  *zoom: 1;
+  *display: inline;
+}
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  height: 100%;
+}
+.CodeMirror-gutter-elt {
+  position: absolute;
+  cursor: default;
+  z-index: 4;
+}
+.CodeMirror-gutter-wrapper {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+.CodeMirror-lines {
+  cursor: text;
+  min-height: 1px;
+  /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  border-radius: 0;
+  border-width: 0;
+  background: transparent;
+  font-family: inherit;
+  font-size: inherit;
+  margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: 2em;
+  color: inherit;
+  z-index: 2;
+  position: relative;
+  overflow: visible;
+  -webkit-tap-highlight-color: transparent;
+}
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+.CodeMirror-linebackground {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  z-index: 0;
+}
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  overflow: auto;
+}
+.CodeMirror-code {
+  outline: none;
+}
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+.CodeMirror-measure pre {
+  position: static;
+}
+.CodeMirror div.CodeMirror-cursor {
+  position: absolute;
+  border-right: none;
+  width: 0;
+}
+div.CodeMirror-cursors {
+  visibility: hidden;
+  position: relative;
+  z-index: 3;
+}
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+.CodeMirror-selected {
+  background: #d9d9d9;
+}
+.CodeMirror-focused .CodeMirror-selected {
+  background: #d7d4f0;
+}
+.CodeMirror-crosshair {
+  cursor: crosshair;
+}
+.CodeMirror-line::selection,
+.CodeMirror-line > span::selection,
+.CodeMirror-line > span > span::selection {
+  background: #d7d4f0;
+}
+.CodeMirror-line::-moz-selection,
+.CodeMirror-line > span::-moz-selection,
+.CodeMirror-line > span > span::-moz-selection {
+  background: #d7d4f0;
+}
+.cm-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, 0.4);
+}
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span {
+  *vertical-align: text-bottom;
+}
+/* Used to force a border model for a node */
+.cm-force-border {
+  padding-right: .1px;
+}
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+/* See issue #2901 */
+.cm-tab-wrap-hack:after {
+  content: '';
+}
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext {
+  background: none;
+}
+/*addon: show-hint*/
+.CodeMirror-hints {
+  position: absolute;
+  z-index: 10000;
+  overflow: hidden;
+  list-style: none;
+  margin: 0;
+  padding: 2px;
+  -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
+  -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
+  box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+  border: 1px solid silver;
+  background: white;
+  font-size: 90%;
+  font-family: monospace;
+  max-height: 20em;
+  overflow-y: auto;
+}
+.CodeMirror-hint {
+  margin: 0;
+  padding: 0 4px;
+  border-radius: 2px;
+  max-width: 19em;
+  overflow: hidden;
+  white-space: pre;
+  color: black;
+  cursor: pointer;
+}
+li.CodeMirror-hint-active {
+  background: #08f;
+  color: white;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-message-mask {
+  background-color: #1a1a1a;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+.bi-message-title {
+  background-color: #f4f4f4;
+  color: #808080;
+  font-size: 16px;
+  cursor: pointer;
+}
+.bi-message-text {
+  font-size: 16px;
+  -webkit-user-select: text;
+  -khtml-user-select: text;
+  -moz-user-select: text;
+  -ms-user-select: text;
+  -o-user-select: text;
+  user-select: text;
+}
+.bi-message-content {
+  background-color: #ffffff;
+  color: #808080;
+  font-size: 16px;
+}
+.bi-message-close {
+  font-size: 25px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-list-view .bi-button-mask {
+  opacity: 0.1;
+  filter: alpha(opacity=10);
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-popup-panel .popup-panel-title {
+  background: #f4f4f4;
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-searcher-view {
+  background: #ffffff;
+}
+.bi-searcher-view .searcher-view-spliter {
+  background: #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-panel {
+  border: 1px solid #a3d6e8;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-panel .panel-title {
+  background-color: #d8f2fd;
+  border-bottom: 1px solid #a3d6e8;
+}
+.bi-panel .panel-title .panel-title-text {
+  cursor: text;
+  color: #808080;
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-all-pager .pager-editor {
+  background-color: #ffffff;
+}
+.bi-all-pager .all-pager-prev {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+.bi-all-pager .all-pager-next {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-pager .page-item {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-pager .page-item.active {
+  background: #009de3;
+  color: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-direction-pager .direction-pager-prev {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+.bi-direction-pager .direction-pager-next {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-number-pager .number-pager-prev {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+.bi-number-pager .number-pager-next {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-skip-pager .skip-pager-prev {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+.bi-skip-pager .skip-pager-next {
+  font-size: 16px;
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-request-loading .mask-pane {
+  background: #ffffff;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+.bi-request-loading .loading-comment {
+  font-size: 14px;
+}
+.bi-request-loading .load-fail-comment {
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-segment-button:active,
+.bi-segment-button.active {
+  color: #ffffff;
+  background: #009de3;
+}
+.bi-segment-button.disabled,
+.bi-segment-button.disabled:hover,
+.bi-segment-button.disabled:active {
+  color: #1a1a1a;
+  background: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-segment > .center-element {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  background: #ffffff;
+  border-right: 1px solid #d4dadd;
+  border-top: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-segment > .first-element {
+  border-left: 1px solid #d4dadd;
+  -webkit-border-radius: 6px 0px 0px 6px;
+  -moz-border-radius: 6px 0px 0px 6px;
+  border-radius: 6px 0px 0px 6px;
+}
+.bi-segment > .last-element {
+  -webkit-border-radius: 0px 6px 6px 0px;
+  -moz-border-radius: 0px 6px 6px 0px;
+  border-radius: 0px 6px 6px 0px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-loading-bar .loading-text {
+  color: #808080;
+}
+.bi-loading-bar .loading-text:hover,
+.bi-loading-bar .loading-text.hover {
+  color: #009de3;
+}
+.bi-loading-bar .loading-text.disabled,
+.bi-loading-bar .loading-text.disabled:hover,
+.bi-loading-bar .loading-text.disabled:active {
+  color: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #009de3;
+  background-color: #009de3;
+  text-align: center;
+  vertical-align: middle;
+  cursor: pointer !important;
+  font-size: 14px;
+}
+.bi-button.button-common,
+.bi-button.button-common .b-font {
+  color: #ffffff;
+}
+.bi-button.button-common .b-font:before {
+  color: #ffffff;
+}
+.bi-button.button-ignore {
+  background-color: #ffffff;
+  border-color: #d4dadd;
+}
+.bi-button.button-ignore,
+.bi-button.button-ignore .b-font {
+  color: #1a1a1a;
+}
+.bi-button.button-success {
+  background-color: #58cc7d;
+  border-color: #58cc7d;
+}
+.bi-button.button-success,
+.bi-button.button-success .b-font {
+  color: #ffffff;
+}
+.bi-button.button-success .b-font:before {
+  color: #ffffff;
+}
+.bi-button.button-warning {
+  background-color: #e85050;
+  border-color: #e85050;
+}
+.bi-button.button-warning,
+.bi-button.button-warning .b-font {
+  color: #ffffff;
+}
+.bi-button.button-warning .b-font:before {
+  color: #ffffff;
+}
+.bi-button.button-common.disabled,
+.bi-button.button-success.disabled,
+.bi-button.button-warning.disabled {
+  background: #c4c6c6 !important;
+  border-color: #c4c6c6 !important;
+}
+.bi-button.button-common.disabled,
+.bi-button.button-success.disabled,
+.bi-button.button-warning.disabled,
+.bi-button.button-common.disabled .b-font,
+.bi-button.button-success.disabled .b-font,
+.bi-button.button-warning.disabled .b-font {
+  color: #ffffff !important;
+}
+.bi-button.button-common.disabled .b-font:before,
+.bi-button.button-success.disabled .b-font:before,
+.bi-button.button-warning.disabled .b-font:before {
+  color: #ffffff !important;
+}
+.bi-button.button-ignore.disabled {
+  background: #ffffff !important;
+  border-color: #d4dadd !important;
+}
+.bi-button.button-ignore.disabled,
+.bi-button.button-ignore.disabled .b-font {
+  color: #c4c6c6 !important;
+}
+.bi-button.button-ignore.disabled .b-font:before {
+  color: #c4c6c6 !important;
+}
+.bi-basic-button.button-common .bi-button-mask,
+.bi-basic-button.button-success .bi-button-mask,
+.bi-basic-button.button-warning .bi-button-mask {
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+  background-color: #ffffff;
+}
+.bi-basic-button .bi-button-mask {
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+  background-color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-single-select-icon-text-item:active .b-font:before,
+.bi-single-select-icon-text-item.active .b-font:before {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-editor {
+  font-size: 12px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multifile-editor .multifile-editor {
+  text-align: right;
+  cursor: pointer;
+  font-size: 100px;
+  z-index: 2;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-record-editor .record-editor-text {
+  font-size: 12px;
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-shelter-editor .shelter-editor-text {
+  font-size: 12px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sign-editor .sign-editor-text {
+  font-size: 12px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-state-editor {
+  font-size: 12px;
+}
+.bi-state-editor .state-editor-infinite-text {
+  font-size: 12px;
+  color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-simple-state-editor {
+  font-size: 12px;
+}
+.bi-simple-state-editor .state-editor-infinite-text {
+  font-size: 12px;
+  color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-textarea-editor {
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+.bi-textarea-editor .textarea-editor-content {
+  font-size: 12px;
+}
+.bi-textarea-editor .textarea-editor-content {
+  border: none;
+}
+.bi-textarea-editor .textarea-editor-content.textarea-editor-focus {
+  border: 1px solid #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file {
+  opacity: 0;
+  filter: alpha(opacity=0);
+  z-index: 2;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-input {
+  border: none;
+  outline: none;
+  background-color: transparent;
+  padding: 0;
+  margin: 0;
+  width: 100%;
+  height: 100%;
+}
+.bi-input.bi-input-focus {
+  border: none;
+}
+.bi-input.bi-input-error {
+  border: none;
+  color: #e85050 !important;
+}
+.bi-input.disabled {
+  background-color: white;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text {
+  text-overflow: ellipsis;
+  overflow-x: hidden;
+  white-space: nowrap;
+  word-break: break-word;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-bubble {
+  font-size: 14px;
+}
+.bi-bubble .bubble-text {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #fddddd;
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tip {
+  position: fixed !important;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-toast {
+  font-size: 14px;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-toast.toast-success {
+  background: #e1f4e7;
+  color: #0c6d23;
+}
+.bi-toast.toast-warning {
+  background: #fddddd;
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tooltip {
+  max-width: 250px;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  font-size: 12px;
+}
+.bi-tooltip.tooltip-success {
+  background: #fff5c1;
+  border: 1px solid #fff5c1;
+  color: #1a1a1a;
+}
+.bi-tooltip.tooltip-warning {
+  background: #fddddd;
+  color: #e85050;
+  border: 1px solid #f4cbcb;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-collection-table-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+.bi-collection-table-cell.first-row {
+  border-top: 1px solid #eaeaea;
+}
+.bi-collection-table-cell.first-col {
+  border-left: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-quick-collection-table > div > .bi-collection {
+  overflow: hidden !important;
+  overflow-x: hidden !important;
+  overflow-y: hidden !important;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-table > .first-col {
+  border-left: none;
+}
+.bi-table > .first-row {
+  border-top: none;
+}
+.bi-table > div > div > table {
+  border-bottom: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+}
+.bi-table > div.top-left > div > div > table {
+  border-bottom: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+}
+.bi-table > div.top-right > div > div > table {
+  border-bottom: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+}
+.bi-table > div.bottom-left > div > div > table {
+  border-bottom: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+}
+.bi-table > div.bottom-right > div > div > table {
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+.bi-table > div > div > table,
+.bi-table > div > div > div > table {
+  min-width: 100%;
+  clear: both;
+  vertical-align: middle;
+  border-spacing: 0;
+  border-collapse: separate;
+}
+.bi-table > div > div > table,
+.bi-table > div > div > div > table,
+.bi-table > div > div > table > * > * > th,
+.bi-table > div > div > div > table > * > * > th,
+.bi-table > div > div > table > * > * > td,
+.bi-table > div > div > div > table > * > * > td {
+  vertical-align: middle;
+  margin: 0;
+  padding: 0;
+}
+.bi-table > div > div > table > tbody > tr > td,
+.bi-table > div > div > div > table > tbody > tr > td,
+.bi-table > div > div > table > thead > tr > td,
+.bi-table > div > div > div > table > thead > tr > td {
+  border-top: 1px solid #eaeaea;
+  border-left: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-grid-table-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+.bi-grid-table-cell.first-row {
+  border-top: 1px solid #eaeaea;
+}
+.bi-grid-table-cell.first-col {
+  border-left: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.scrollbar-layout-main {
+  box-sizing: border-box;
+  outline: none;
+  overflow: hidden;
+  position: absolute;
+  transition-duration: 250ms;
+  transition-timing-function: ease;
+  user-select: none;
+  background-color: rgba(0, 0, 0, 0.1);
+  border-radius: 5px;
+}
+.scrollbar-layout-main-vertical {
+  bottom: 0;
+  right: 0;
+  top: 0;
+  transition-property: background-color;
+  width: 10px;
+}
+.scrollbar-layout-main-vertical.public-scrollbar-main-active,
+.scrollbar-layout-main-vertical:hover {
+  width: 10px;
+}
+.scrollbar-layout-main-horizontal {
+  bottom: 0;
+  height: 10px;
+  left: 0;
+  transition-property: background-color;
+  background-color: rgba(0, 0, 0, 0.1);
+}
+/* Touching the scroll-track directly makes the scroll-track bolder */
+.scrollbar-layout-main-horizontal.public-scrollbar-main-active,
+.scrollbar-layout-main-horizontal:hover {
+  height: 10px;
+}
+.scrollbar-layout-face {
+  left: 0;
+  overflow: hidden;
+  position: absolute;
+  z-index: 1;
+}
+/**
+ * This selector renders the "nub" of the scrollface. The nub must
+ * be rendered as pseudo-element so that it won't receive any UI events then
+ * we can get the correct `event.offsetX` and `event.offsetY` from the
+ * scrollface element while dragging it.
+ */
+.scrollbar-layout-face:after {
+  border-radius: 6px;
+  content: '';
+  display: block;
+  position: absolute;
+  transition: background-color 250ms ease;
+}
+.scrollbar-layout-face-horizontal {
+  bottom: 0;
+  left: 0;
+  top: 0;
+}
+.scrollbar-layout-face-horizontal:after {
+  bottom: 2px;
+  left: 0;
+  top: 2px;
+  width: 100%;
+}
+.scrollbar-layout-face-vertical {
+  left: 0;
+  right: 0;
+  top: 0;
+}
+.scrollbar-layout-face-vertical:after {
+  height: 100%;
+  left: 2px;
+  right: 2px;
+  top: 0;
+}
+/**
+ * scrollbars.
+ */
+/* Touching the scroll-track directly makes the scroll-track bolder */
+.public-scrollbar-face:after {
+  background-color: #c2c2c2;
+}
+.public-scrollbar-main:hover .public-scrollbar-face:after,
+.public-scrollbar-main-active .public-scrollbar-face:after,
+.public-scrollbar-faceActive:after {
+  background-color: #7d7d7d;
+}
+.horizontal-scrollbar {
+  bottom: 0;
+  position: absolute;
+}
+.horizontal-scrollbar .public-scrollbar-main-horizontal {
+  background-color: #fff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-resizable-table-cell .resizable-table-cell-resizer-container {
+  cursor: ew-resize;
+  z-index: 1;
+}
+.bi-resizable-table-cell .resizable-table-cell-resizer-container:hover .resizable-table-cell-resizer-knob,
+.bi-resizable-table-cell .resizable-table-cell-resizer-container.dragging .resizable-table-cell-resizer-knob {
+  background-color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-resizable-table .resizable-table-resizer {
+  cursor: ew-resize;
+  z-index: 1;
+  background-color: #009de3;
+}
+.bi-resizable-table .resizable-table-region-resizer {
+  cursor: ew-resize;
+  z-index: 1;
+}
+.bi-resizable-table .resizable-table-region-resizer:hover .resizable-table-region-resizer-knob,
+.bi-resizable-table .resizable-table-region-resizer.dragging .resizable-table-region-resizer-knob {
+  background-color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/**
+ * Farbtastic Color Picker 1.2
+ * © 2008 Steven Wittens
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+.farbtastic {
+  position: relative;
+}
+.farbtastic * {
+  position: absolute;
+  cursor: crosshair;
+}
+.farbtastic,
+.farbtastic .wheel {
+  width: 195px;
+  height: 195px;
+}
+.farbtastic .color,
+.farbtastic .overlay {
+  top: 47px;
+  left: 47px;
+  width: 101px;
+  height: 101px;
+}
+.farbtastic .wheel {
+  background: url(${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/farbtastic/wheel.png) no-repeat;
+  width: 195px;
+  height: 195px;
+}
+.farbtastic .overlay {
+  background: url(${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/farbtastic/mask.png) no-repeat;
+}
+.farbtastic .marker {
+  width: 17px;
+  height: 17px;
+  margin: -8px 0 0 -8px;
+  overflow: hidden;
+  background: url(${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/farbtastic/marker.png) no-repeat;
+}
+/*
+== malihu jquery custom scrollbar plugin ==
+Plugin URI: http://manos.malihu.gr/jquery-custom-content-scroller
+*/
+/*
+CONTENTS:
+	1. BASIC STYLE - Plugin's basic/essential CSS properties (normally, should not be edited).
+	2. VERTICAL SCROLLBAR - Positioning and dimensions of vertical scrollbar.
+	3. HORIZONTAL SCROLLBAR - Positioning and dimensions of horizontal scrollbar.
+	4. VERTICAL AND HORIZONTAL SCROLLBARS - Positioning and dimensions of 2-axis scrollbars.
+	5. TRANSITIONS - CSS3 transitions for hover events, auto-expanded and auto-hidden scrollbars.
+	6. SCROLLBAR COLORS, OPACITY AND BACKGROUNDS
+		6.1 THEMES - Scrollbar colors, opacity, dimensions, backgrounds etc. via ready-to-use themes.
+*/
+/*
+------------------------------------------------------------------------------------------------------------------------
+1. BASIC STYLE
+------------------------------------------------------------------------------------------------------------------------
+*/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.mCustomScrollbar {
+  -ms-touch-action: pinch-zoom;
+  touch-action: pinch-zoom;
+  /* direct pointer events to js */
+}
+.mCustomScrollbar.mCS_no_scrollbar,
+.mCustomScrollbar.mCS_touch_action {
+  -ms-touch-action: auto;
+  touch-action: auto;
+}
+.mCustomScrollBox {
+  /* contains plugin's markup */
+  position: relative;
+  overflow: hidden;
+  height: 100%;
+  max-width: 100%;
+  outline: none;
+  direction: ltr;
+}
+.mCSB_container {
+  /* contains the original content */
+  overflow: hidden;
+  width: auto;
+  height: auto;
+}
+/*
+------------------------------------------------------------------------------------------------------------------------
+2. VERTICAL SCROLLBAR
+y-axis
+------------------------------------------------------------------------------------------------------------------------
+*/
+.mCSB_inside > .mCSB_container {
+  margin-right: 30px;
+}
+.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden {
+  margin-right: 0;
+}
+/* non-visible scrollbar */
+.mCS-dir-rtl > .mCSB_inside > .mCSB_container {
+  /* RTL direction/left-side scrollbar */
+  margin-right: 0;
+  margin-left: 30px;
+}
+.mCS-dir-rtl > .mCSB_inside > .mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden {
+  margin-left: 0;
+}
+/* RTL direction/left-side scrollbar */
+.mCSB_scrollTools {
+  /* contains scrollbar markup (draggable element, dragger rail, buttons etc.) */
+  position: absolute;
+  width: 16px;
+  height: auto;
+  left: auto;
+  top: 0;
+  right: 0;
+  bottom: 0;
+}
+.mCSB_outside + .mCSB_scrollTools {
+  right: -26px;
+}
+/* scrollbar position: outside */
+.mCS-dir-rtl > .mCSB_inside > .mCSB_scrollTools,
+.mCS-dir-rtl > .mCSB_outside + .mCSB_scrollTools {
+  /* RTL direction/left-side scrollbar */
+  right: auto;
+  left: 0;
+}
+.mCS-dir-rtl > .mCSB_outside + .mCSB_scrollTools {
+  left: -26px;
+}
+/* RTL direction/left-side scrollbar (scrollbar position: outside) */
+.mCSB_scrollTools .mCSB_draggerContainer {
+  /* contains the draggable element and dragger rail markup */
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  height: auto;
+}
+.mCSB_scrollTools a + .mCSB_draggerContainer {
+  margin: 20px 0;
+}
+.mCSB_scrollTools .mCSB_draggerRail {
+  width: 2px;
+  height: 100%;
+  margin: 0 auto;
+  -webkit-border-radius: 16px;
+  -moz-border-radius: 16px;
+  border-radius: 16px;
+}
+.mCSB_scrollTools .mCSB_dragger {
+  /* the draggable element */
+  cursor: pointer;
+  width: 100%;
+  height: 30px;
+  /* minimum dragger height */
+  z-index: 1;
+}
+.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  /* the dragger element */
+  position: relative;
+  width: 4px;
+  height: 100%;
+  margin: 0 auto;
+  -webkit-border-radius: 16px;
+  -moz-border-radius: 16px;
+  border-radius: 16px;
+  text-align: center;
+}
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar {
+  width: 12px;
+  /* auto-expanded scrollbar */
+}
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  width: 8px;
+  /* auto-expanded scrollbar */
+}
+.mCSB_scrollTools .mCSB_buttonUp,
+.mCSB_scrollTools .mCSB_buttonDown {
+  display: block;
+  position: absolute;
+  height: 20px;
+  width: 100%;
+  overflow: hidden;
+  margin: 0 auto;
+  cursor: pointer;
+}
+.mCSB_scrollTools .mCSB_buttonDown {
+  bottom: 0;
+}
+/*
+------------------------------------------------------------------------------------------------------------------------
+3. HORIZONTAL SCROLLBAR
+x-axis
+------------------------------------------------------------------------------------------------------------------------
+*/
+.mCSB_horizontal.mCSB_inside > .mCSB_container {
+  margin-right: 0;
+  margin-bottom: 30px;
+}
+.mCSB_horizontal.mCSB_outside > .mCSB_container {
+  min-height: 100%;
+}
+.mCSB_horizontal > .mCSB_container.mCS_no_scrollbar_x.mCS_x_hidden {
+  margin-bottom: 0;
+}
+/* non-visible scrollbar */
+.mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  width: auto;
+  height: 16px;
+  top: auto;
+  right: 0;
+  bottom: 0;
+  left: 0;
+}
+.mCustomScrollBox + .mCSB_scrollTools.mCSB_scrollTools_horizontal,
+.mCustomScrollBox + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  bottom: -26px;
+}
+/* scrollbar position: outside */
+.mCSB_scrollTools.mCSB_scrollTools_horizontal a + .mCSB_draggerContainer {
+  margin: 0 20px;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 2px;
+  margin: 7px 0;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger {
+  width: 30px;
+  /* minimum dragger width */
+  height: 100%;
+  left: 0;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 4px;
+  margin: 6px auto;
+}
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar {
+  height: 12px;
+  /* auto-expanded scrollbar */
+  margin: 2px auto;
+}
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  height: 8px;
+  /* auto-expanded scrollbar */
+  margin: 4px 0;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft,
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight {
+  display: block;
+  position: absolute;
+  width: 20px;
+  height: 100%;
+  overflow: hidden;
+  margin: 0 auto;
+  cursor: pointer;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft {
+  left: 0;
+}
+.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight {
+  right: 0;
+}
+/*
+------------------------------------------------------------------------------------------------------------------------
+4. VERTICAL AND HORIZONTAL SCROLLBARS
+yx-axis
+------------------------------------------------------------------------------------------------------------------------
+*/
+.mCSB_container_wrapper {
+  position: absolute;
+  height: auto;
+  width: auto;
+  overflow: hidden;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  margin-right: 30px;
+  margin-bottom: 30px;
+}
+.mCSB_container_wrapper > .mCSB_container {
+  padding-right: 30px;
+  padding-bottom: 30px;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.mCSB_vertical_horizontal > .mCSB_scrollTools.mCSB_scrollTools_vertical {
+  bottom: 20px;
+}
+.mCSB_vertical_horizontal > .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  right: 20px;
+}
+/* non-visible horizontal scrollbar */
+.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden + .mCSB_scrollTools.mCSB_scrollTools_vertical {
+  bottom: 0;
+}
+/* non-visible vertical scrollbar/RTL direction/left-side scrollbar */
+.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden + .mCSB_scrollTools ~ .mCSB_scrollTools.mCSB_scrollTools_horizontal,
+.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  right: 0;
+}
+/* RTL direction/left-side scrollbar */
+.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  left: 20px;
+}
+/* non-visible scrollbar/RTL direction/left-side scrollbar */
+.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden + .mCSB_scrollTools ~ .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  left: 0;
+}
+.mCS-dir-rtl > .mCSB_inside > .mCSB_container_wrapper {
+  /* RTL direction/left-side scrollbar */
+  margin-right: 0;
+  margin-left: 30px;
+}
+.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden > .mCSB_container {
+  padding-right: 0;
+}
+.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden > .mCSB_container {
+  padding-bottom: 0;
+}
+.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden {
+  margin-right: 0;
+  /* non-visible scrollbar */
+  margin-left: 0;
+}
+/* non-visible horizontal scrollbar */
+.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden {
+  margin-bottom: 0;
+}
+/*
+------------------------------------------------------------------------------------------------------------------------
+5. TRANSITIONS
+------------------------------------------------------------------------------------------------------------------------
+*/
+.mCSB_scrollTools,
+.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCSB_scrollTools .mCSB_buttonUp,
+.mCSB_scrollTools .mCSB_buttonDown,
+.mCSB_scrollTools .mCSB_buttonLeft,
+.mCSB_scrollTools .mCSB_buttonRight {
+  -webkit-transition: opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  -moz-transition: opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  -o-transition: opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  transition: opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+}
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar,
+.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail,
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar,
+.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail {
+  -webkit-transition: width 0.2s ease-out 0.2s, height 0.2s ease-out 0.2s, margin-left 0.2s ease-out 0.2s, margin-right 0.2s ease-out 0.2s, margin-top 0.2s ease-out 0.2s, margin-bottom 0.2s ease-out 0.2s, opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  -moz-transition: width 0.2s ease-out 0.2s, height 0.2s ease-out 0.2s, margin-left 0.2s ease-out 0.2s, margin-right 0.2s ease-out 0.2s, margin-top 0.2s ease-out 0.2s, margin-bottom 0.2s ease-out 0.2s, opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  -o-transition: width 0.2s ease-out 0.2s, height 0.2s ease-out 0.2s, margin-left 0.2s ease-out 0.2s, margin-right 0.2s ease-out 0.2s, margin-top 0.2s ease-out 0.2s, margin-bottom 0.2s ease-out 0.2s, opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+  transition: width 0.2s ease-out 0.2s, height 0.2s ease-out 0.2s, margin-left 0.2s ease-out 0.2s, margin-right 0.2s ease-out 0.2s, margin-top 0.2s ease-out 0.2s, margin-bottom 0.2s ease-out 0.2s, opacity 0.2s ease-in-out, background-color 0.2s ease-in-out;
+}
+/*
+------------------------------------------------------------------------------------------------------------------------
+6. SCROLLBAR COLORS, OPACITY AND BACKGROUNDS
+------------------------------------------------------------------------------------------------------------------------
+*/
+/*
+----------------------------------------
+6.1 THEMES
+----------------------------------------
+*/
+/* default theme ("light") */
+.mCSB_scrollTools {
+  opacity: 0.75;
+  filter: "alpha(opacity=75)";
+  -ms-filter: "alpha(opacity=75)";
+}
+.mCS-autoHide > .mCustomScrollBox > .mCSB_scrollTools,
+.mCS-autoHide > .mCustomScrollBox ~ .mCSB_scrollTools {
+  opacity: 0;
+  filter: "alpha(opacity=0)";
+  -ms-filter: "alpha(opacity=0)";
+}
+.mCustomScrollbar > .mCustomScrollBox > .mCSB_scrollTools.mCSB_scrollTools_onDrag,
+.mCustomScrollbar > .mCustomScrollBox ~ .mCSB_scrollTools.mCSB_scrollTools_onDrag,
+.mCustomScrollBox:hover > .mCSB_scrollTools,
+.mCustomScrollBox:hover ~ .mCSB_scrollTools,
+.mCS-autoHide:hover > .mCustomScrollBox > .mCSB_scrollTools,
+.mCS-autoHide:hover > .mCustomScrollBox ~ .mCSB_scrollTools {
+  opacity: 1;
+  filter: "alpha(opacity=100)";
+  -ms-filter: "alpha(opacity=100)";
+}
+.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.4);
+  filter: "alpha(opacity=40)";
+  -ms-filter: "alpha(opacity=40)";
+}
+.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.75);
+  filter: "alpha(opacity=75)";
+  -ms-filter: "alpha(opacity=75)";
+}
+.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.85);
+  filter: "alpha(opacity=85)";
+  -ms-filter: "alpha(opacity=85)";
+}
+.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.9);
+  filter: "alpha(opacity=90)";
+  -ms-filter: "alpha(opacity=90)";
+}
+.mCSB_scrollTools .mCSB_buttonUp,
+.mCSB_scrollTools .mCSB_buttonDown,
+.mCSB_scrollTools .mCSB_buttonLeft,
+.mCSB_scrollTools .mCSB_buttonRight {
+  background-image: url('background/mCSB_buttons.png');
+  /* css sprites */
+  background-repeat: no-repeat;
+  opacity: 0.4;
+  filter: "alpha(opacity=40)";
+  -ms-filter: "alpha(opacity=40)";
+}
+.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: 0 0;
+  /*
+  sprites locations
+  light: 0 0, -16px 0, -32px 0, -48px 0, 0 -72px, -16px -72px, -32px -72px
+  dark: -80px 0, -96px 0, -112px 0, -128px 0, -80px -72px, -96px -72px, -112px -72px
+  */
+}
+.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: 0 -20px;
+  /*
+  sprites locations
+  light: 0 -20px, -16px -20px, -32px -20px, -48px -20px, 0 -92px, -16px -92px, -32px -92px
+  dark: -80px -20px, -96px -20px, -112px -20px, -128px -20px, -80px -92px, -96px -92px, -112 -92px
+  */
+}
+.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: 0 -40px;
+  /*
+  sprites locations
+  light: 0 -40px, -20px -40px, -40px -40px, -60px -40px, 0 -112px, -20px -112px, -40px -112px
+  dark: -80px -40px, -100px -40px, -120px -40px, -140px -40px, -80px -112px, -100px -112px, -120px -112px
+  */
+}
+.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: 0 -56px;
+  /*
+  sprites locations
+  light: 0 -56px, -20px -56px, -40px -56px, -60px -56px, 0 -128px, -20px -128px, -40px -128px
+  dark: -80px -56px, -100px -56px, -120px -56px, -140px -56px, -80px -128px, -100px -128px, -120px -128px
+  */
+}
+.mCSB_scrollTools .mCSB_buttonUp:hover,
+.mCSB_scrollTools .mCSB_buttonDown:hover,
+.mCSB_scrollTools .mCSB_buttonLeft:hover,
+.mCSB_scrollTools .mCSB_buttonRight:hover {
+  opacity: 0.75;
+  filter: "alpha(opacity=75)";
+  -ms-filter: "alpha(opacity=75)";
+}
+.mCSB_scrollTools .mCSB_buttonUp:active,
+.mCSB_scrollTools .mCSB_buttonDown:active,
+.mCSB_scrollTools .mCSB_buttonLeft:active,
+.mCSB_scrollTools .mCSB_buttonRight:active {
+  opacity: 0.9;
+  filter: "alpha(opacity=90)";
+  -ms-filter: "alpha(opacity=90)";
+}
+/* theme: "dark" */
+.mCS-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.15);
+}
+.mCS-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -80px 0;
+}
+.mCS-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -80px -20px;
+}
+.mCS-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -80px -40px;
+}
+.mCS-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -80px -56px;
+}
+/* ---------------------------------------- */
+/* theme: "light-2", "dark-2" */
+.mCS-light-2.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail {
+  width: 4px;
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.1);
+  -webkit-border-radius: 1px;
+  -moz-border-radius: 1px;
+  border-radius: 1px;
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 4px;
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.75);
+  -webkit-border-radius: 1px;
+  -moz-border-radius: 1px;
+  border-radius: 1px;
+}
+.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 4px;
+  margin: 6px auto;
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.85);
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-light-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -32px 0;
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -32px -20px;
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -40px -40px;
+}
+.mCS-light-2.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -40px -56px;
+}
+/* theme: "dark-2" */
+.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.1);
+  -webkit-border-radius: 1px;
+  -moz-border-radius: 1px;
+  border-radius: 1px;
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+  -webkit-border-radius: 1px;
+  -moz-border-radius: 1px;
+  border-radius: 1px;
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -112px 0;
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -112px -20px;
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -120px -40px;
+}
+.mCS-dark-2.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -120px -56px;
+}
+/* ---------------------------------------- */
+/* theme: "light-thick", "dark-thick" */
+.mCS-light-thick.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail {
+  width: 4px;
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.1);
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 6px;
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.75);
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 4px;
+  margin: 6px 0;
+}
+.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 6px;
+  margin: 5px auto;
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.85);
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-light-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -16px 0;
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -16px -20px;
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -20px -40px;
+}
+.mCS-light-thick.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -20px -56px;
+}
+/* theme: "dark-thick" */
+.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.1);
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -96px 0;
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -96px -20px;
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -100px -40px;
+}
+.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -100px -56px;
+}
+/* ---------------------------------------- */
+/* theme: "light-thin", "dark-thin" */
+.mCS-light-thin.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.1);
+}
+.mCS-light-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 2px;
+}
+.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+}
+.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 2px;
+  margin: 7px auto;
+}
+/* theme "dark-thin" */
+.mCS-dark-thin.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.15);
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -80px 0;
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -80px -20px;
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -80px -40px;
+}
+.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -80px -56px;
+}
+/* ---------------------------------------- */
+/* theme "rounded", "rounded-dark", "rounded-dots", "rounded-dots-dark" */
+.mCS-rounded.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.15);
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_dragger,
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger,
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger {
+  height: 14px;
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 14px;
+  margin: 0 1px;
+}
+.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger,
+.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger,
+.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger {
+  width: 14px;
+}
+.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  height: 14px;
+  margin: 1px 0;
+}
+.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar {
+  width: 16px;
+  /* auto-expanded scrollbar */
+  height: 16px;
+  margin: -1px 0;
+}
+.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,
+.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  width: 4px;
+  /* auto-expanded scrollbar */
+}
+.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar {
+  height: 16px;
+  /* auto-expanded scrollbar */
+  width: 16px;
+  margin: 0 -1px;
+}
+.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  height: 4px;
+  /* auto-expanded scrollbar */
+  margin: 6px 0;
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: 0 -72px;
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: 0 -92px;
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: 0 -112px;
+}
+.mCS-rounded.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: 0 -128px;
+}
+/* theme "rounded-dark", "rounded-dots-dark" */
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.15);
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -80px -72px;
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -80px -92px;
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -80px -112px;
+}
+.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -80px -128px;
+}
+/* theme "rounded-dots", "rounded-dots-dark" */
+.mCS-rounded-dots.mCSB_scrollTools_vertical .mCSB_draggerRail,
+.mCS-rounded-dots-dark.mCSB_scrollTools_vertical .mCSB_draggerRail {
+  width: 4px;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  background-color: transparent;
+  background-position: center;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAANElEQVQYV2NkIAAYiVbw//9/Y6DiM1ANJoyMjGdBbLgJQAX/kU0DKgDLkaQAvxW4HEvQFwCRcxIJK1XznAAAAABJRU5ErkJggg==");
+  background-repeat: repeat-y;
+  opacity: 0.3;
+  filter: "alpha(opacity=30)";
+  -ms-filter: "alpha(opacity=30)";
+}
+.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  height: 4px;
+  margin: 6px 0;
+  background-repeat: repeat-x;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -16px -72px;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -16px -92px;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -20px -112px;
+}
+.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -20px -128px;
+}
+/* theme "rounded-dots-dark" */
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAALElEQVQYV2NkIAAYSVFgDFR8BqrBBEifBbGRTfiPZhpYjiQFBK3A6l6CvgAAE9kGCd1mvgEAAAAASUVORK5CYII=");
+}
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -96px -72px;
+}
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -96px -92px;
+}
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -100px -112px;
+}
+.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -100px -128px;
+}
+/* ---------------------------------------- */
+/* theme "3d", "3d-dark", "3d-thick", "3d-thick-dark" */
+.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-repeat: repeat-y;
+  background-image: -moz-linear-gradient(left, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0.5)), color-stop(100%, rgba(255, 255, 255, 0)));
+  background-image: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -o-linear-gradient(left, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -ms-linear-gradient(left, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: linear-gradient(to right, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+}
+.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  background-repeat: repeat-x;
+  background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(255, 255, 255, 0.5)), color-stop(100%, rgba(255, 255, 255, 0)));
+  background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: -ms-linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+  background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
+}
+/* theme "3d", "3d-dark" */
+.mCS-3d.mCSB_scrollTools_vertical .mCSB_dragger,
+.mCS-3d-dark.mCSB_scrollTools_vertical .mCSB_dragger {
+  height: 70px;
+}
+.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger,
+.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger {
+  width: 70px;
+}
+.mCS-3d.mCSB_scrollTools,
+.mCS-3d-dark.mCSB_scrollTools {
+  opacity: 1;
+  filter: "alpha(opacity=30)";
+  -ms-filter: "alpha(opacity=30)";
+}
+.mCS-3d.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  -webkit-border-radius: 16px;
+  -moz-border-radius: 16px;
+  border-radius: 16px;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail {
+  width: 8px;
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.2);
+  box-shadow: inset 1px 0 1px rgba(0, 0, 0, 0.5), inset -1px 0 1px rgba(255, 255, 255, 0.2);
+}
+.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-3d.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-3d.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #555;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 8px;
+}
+.mCS-3d.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 8px;
+  margin: 4px 0;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.5), inset 0 -1px 1px rgba(255, 255, 255, 0.2);
+}
+.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 8px;
+  margin: 4px auto;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -32px -72px;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -32px -92px;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -40px -112px;
+}
+.mCS-3d.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -40px -128px;
+}
+/* theme "3d-dark" */
+.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.1);
+  box-shadow: inset 1px 0 1px rgba(0, 0, 0, 0.1);
+}
+.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
+}
+.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -112px -72px;
+}
+.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -112px -92px;
+}
+.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -120px -112px;
+}
+.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -120px -128px;
+}
+/* ---------------------------------------- */
+/* theme: "3d-thick", "3d-thick-dark" */
+.mCS-3d-thick.mCSB_scrollTools,
+.mCS-3d-thick-dark.mCSB_scrollTools {
+  opacity: 1;
+  filter: "alpha(opacity=30)";
+  -ms-filter: "alpha(opacity=30)";
+}
+.mCS-3d-thick.mCSB_scrollTools,
+.mCS-3d-thick-dark.mCSB_scrollTools,
+.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer {
+  -webkit-border-radius: 7px;
+  -moz-border-radius: 7px;
+  border-radius: 7px;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+}
+.mCSB_inside + .mCS-3d-thick.mCSB_scrollTools_vertical,
+.mCSB_inside + .mCS-3d-thick-dark.mCSB_scrollTools_vertical {
+  right: 1px;
+}
+.mCS-3d-thick.mCSB_scrollTools_vertical,
+.mCS-3d-thick-dark.mCSB_scrollTools_vertical {
+  box-shadow: inset 1px 0 1px rgba(0, 0, 0, 0.1), inset 0 0 14px rgba(0, 0, 0, 0.5);
+}
+.mCS-3d-thick.mCSB_scrollTools_horizontal,
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal {
+  bottom: 1px;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1), inset 0 0 14px rgba(0, 0, 0, 0.5);
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.4);
+  width: 12px;
+  margin: 2px;
+  position: absolute;
+  height: auto;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+}
+.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #555;
+}
+.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  height: 12px;
+  width: auto;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.05);
+  box-shadow: inset 1px 1px 16px rgba(0, 0, 0, 0.1);
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: transparent;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -32px -72px;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -32px -92px;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -40px -112px;
+}
+.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -40px -128px;
+}
+/* theme: "3d-thick-dark" */
+.mCS-3d-thick-dark.mCSB_scrollTools {
+  box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.2);
+}
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal {
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1), inset 0 0 14px rgba(0, 0, 0, 0.2);
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.4), inset -1px 0 0 rgba(0, 0, 0, 0.2);
+}
+.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), inset 0 -1px 0 rgba(0, 0, 0, 0.2);
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #777;
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer {
+  background-color: #fff;
+  background-color: rgba(0, 0, 0, 0.05);
+  box-shadow: inset 1px 1px 16px rgba(0, 0, 0, 0.1);
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: transparent;
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -112px -72px;
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -112px -92px;
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -120px -112px;
+}
+.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -120px -128px;
+}
+/* ---------------------------------------- */
+/* theme: "minimal", "minimal-dark" */
+.mCSB_outside + .mCS-minimal.mCSB_scrollTools_vertical,
+.mCSB_outside + .mCS-minimal-dark.mCSB_scrollTools_vertical {
+  right: 0;
+  margin: 12px 0;
+}
+.mCustomScrollBox.mCS-minimal + .mCSB_scrollTools.mCSB_scrollTools_horizontal,
+.mCustomScrollBox.mCS-minimal + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal,
+.mCustomScrollBox.mCS-minimal-dark + .mCSB_scrollTools.mCSB_scrollTools_horizontal,
+.mCustomScrollBox.mCS-minimal-dark + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  bottom: 0;
+  margin: 0 12px;
+}
+/* RTL direction/left-side scrollbar */
+.mCS-dir-rtl > .mCSB_outside + .mCS-minimal.mCSB_scrollTools_vertical,
+.mCS-dir-rtl > .mCSB_outside + .mCS-minimal-dark.mCSB_scrollTools_vertical {
+  left: 0;
+  right: auto;
+}
+.mCS-minimal.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-minimal-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: transparent;
+}
+.mCS-minimal.mCSB_scrollTools_vertical .mCSB_dragger,
+.mCS-minimal-dark.mCSB_scrollTools_vertical .mCSB_dragger {
+  height: 50px;
+}
+.mCS-minimal.mCSB_scrollTools_horizontal .mCSB_dragger,
+.mCS-minimal-dark.mCSB_scrollTools_horizontal .mCSB_dragger {
+  width: 50px;
+}
+.mCS-minimal.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.2);
+  filter: "alpha(opacity=20)";
+  -ms-filter: "alpha(opacity=20)";
+}
+.mCS-minimal.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-minimal.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.5);
+  filter: "alpha(opacity=50)";
+  -ms-filter: "alpha(opacity=50)";
+}
+/* theme: "minimal-dark" */
+.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.2);
+  filter: "alpha(opacity=20)";
+  -ms-filter: "alpha(opacity=20)";
+}
+.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.5);
+  filter: "alpha(opacity=50)";
+  -ms-filter: "alpha(opacity=50)";
+}
+/* ---------------------------------------- */
+/* theme "light-3", "dark-3" */
+.mCS-light-3.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail {
+  width: 6px;
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.2);
+}
+.mCS-light-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 6px;
+}
+.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 6px;
+  margin: 5px 0;
+}
+.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  width: 12px;
+}
+.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  height: 12px;
+  margin: 2px 0;
+}
+.mCS-light-3.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -32px -72px;
+}
+.mCS-light-3.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -32px -92px;
+}
+.mCS-light-3.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -40px -112px;
+}
+.mCS-light-3.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -40px -128px;
+}
+/* theme "dark-3" */
+.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-dark-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.1);
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -112px -72px;
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -112px -92px;
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -120px -112px;
+}
+.mCS-dark-3.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -120px -128px;
+}
+/* ---------------------------------------- */
+/* theme "inset", "inset-dark", "inset-2", "inset-2-dark", "inset-3", "inset-3-dark" */
+.mCS-inset.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail {
+  width: 12px;
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.2);
+}
+.mCS-inset.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 6px;
+  margin: 3px 5px;
+  position: absolute;
+  height: auto;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+}
+.mCS-inset.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  height: 6px;
+  margin: 5px 3px;
+  position: absolute;
+  width: auto;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+}
+.mCS-inset.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,
+.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 12px;
+  margin: 2px 0;
+}
+.mCS-inset.mCSB_scrollTools .mCSB_buttonUp,
+.mCS-inset-2.mCSB_scrollTools .mCSB_buttonUp,
+.mCS-inset-3.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -32px -72px;
+}
+.mCS-inset.mCSB_scrollTools .mCSB_buttonDown,
+.mCS-inset-2.mCSB_scrollTools .mCSB_buttonDown,
+.mCS-inset-3.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -32px -92px;
+}
+.mCS-inset.mCSB_scrollTools .mCSB_buttonLeft,
+.mCS-inset-2.mCSB_scrollTools .mCSB_buttonLeft,
+.mCS-inset-3.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -40px -112px;
+}
+.mCS-inset.mCSB_scrollTools .mCSB_buttonRight,
+.mCS-inset-2.mCSB_scrollTools .mCSB_buttonRight,
+.mCS-inset-3.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -40px -128px;
+}
+/* theme "inset-dark", "inset-2-dark", "inset-3-dark" */
+.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.1);
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonUp,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonUp,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -112px -72px;
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonDown,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonDown,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -112px -92px;
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonLeft,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonLeft,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -120px -112px;
+}
+.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonRight,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonRight,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -120px -128px;
+}
+/* theme "inset-2", "inset-2-dark" */
+.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail,
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: transparent;
+  border-width: 1px;
+  border-style: solid;
+  border-color: #fff;
+  border-color: rgba(255, 255, 255, 0.2);
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail {
+  border-color: #000;
+  border-color: rgba(0, 0, 0, 0.2);
+}
+/* theme "inset-3", "inset-3-dark" */
+.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.6);
+}
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.6);
+}
+.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.75);
+}
+.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.85);
+}
+.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-inset-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #000;
+  background-color: rgba(0, 0, 0, 0.9);
+}
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.75);
+}
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.85);
+}
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
+.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar {
+  background-color: #fff;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+/* ---------------------------------------- */
+/* theme "bi-default" */
+.mCS-bi-default {
+  background-color: #dddddd;
+}
+.mCS-bi-default .mCSB_scrollTools.mCSB_scrollTools_horizontal {
+  height: 18px;
+}
+.mCS-bi-default .mCSB_scrollTools.mCSB_scrollTools_vertical {
+  width: 18px;
+}
+.mCS-bi-default .mCSB_scrollTools .mCSB_draggerRail {
+  border-radius: 0px;
+}
+.mCS-bi-default .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  border-radius: 2px;
+}
+.mCS-bi-default .mCSB_scrollTools.mCSB_scrollTools_horizontal a + .mCSB_draggerContainer {
+  margin: 0 18px;
+}
+.mCS-bi-default .mCSB_scrollTools.mCSB_scrollTools_vertical a + .mCSB_draggerContainer {
+  margin: 18px 0;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  width: 14px;
+  margin: 0 2px;
+}
+.mCS-bi-default.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar {
+  width: 100%;
+  height: 14px;
+  margin: 2px auto;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_draggerRail {
+  width: 18px;
+  height: 100%;
+  margin: 0;
+}
+.mCS-bi-default.mCSB_scrollTools_horizontal .mCSB_draggerRail {
+  width: 100%;
+  height: 18px;
+  margin: 0;
+}
+.mCS-bi-default.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-bi-default.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  width: 14px;
+}
+.mCS-bi-default.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail,
+.mCS-bi-default.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail {
+  height: 14px;
+  margin: 2px 0;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
+  background-color: #f4f4f4;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_draggerRail {
+  background-color: #dddddd;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonUp,
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonDown,
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonLeft,
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonRight {
+  width: 16px;
+  height: 16px;
+  background-color: #f4f4f4;
+  border: 1px solid #eaeaea;
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonUp {
+  background-position: -128px -1px;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonDown {
+  background-position: -128px -21px;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonLeft {
+  background-position: -142px -40px;
+}
+.mCS-bi-default.mCSB_scrollTools .mCSB_buttonRight {
+  background-position: -141px -56px;
+}
+/* ---------------------------------------- */
+/* required styles */
+.leaflet-pane,
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow,
+.leaflet-tile-container,
+.leaflet-map-pane svg,
+.leaflet-map-pane canvas,
+.leaflet-zoom-box,
+.leaflet-image-layer,
+.leaflet-layer {
+  position: absolute;
+  left: 0;
+  top: 0;
+}
+.leaflet-container {
+  overflow: hidden;
+  -ms-touch-action: none;
+  touch-action: none;
+}
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+  -webkit-user-drag: none;
+}
+/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
+.leaflet-safari .leaflet-tile {
+  image-rendering: -webkit-optimize-contrast;
+}
+/* hack that prevents hw layers "stretching" when loading new tiles */
+.leaflet-safari .leaflet-tile-container {
+  width: 1600px;
+  height: 1600px;
+  -webkit-transform-origin: 0 0;
+}
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+  display: block;
+}
+/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
+/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
+.leaflet-container .leaflet-overlay-pane svg,
+.leaflet-container .leaflet-marker-pane img,
+.leaflet-container .leaflet-tile-pane img,
+.leaflet-container img.leaflet-image-layer {
+  max-width: none !important;
+}
+.leaflet-tile {
+  filter: inherit;
+  visibility: hidden;
+}
+.leaflet-tile-loaded {
+  visibility: inherit;
+}
+.leaflet-zoom-box {
+  width: 0;
+  height: 0;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  z-index: 800;
+}
+/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
+.leaflet-overlay-pane svg {
+  -moz-user-select: none;
+}
+.leaflet-pane {
+  z-index: 400;
+}
+.leaflet-tile-pane {
+  z-index: 200;
+}
+.leaflet-overlay-pane {
+  z-index: 400;
+}
+.leaflet-shadow-pane {
+  z-index: 500;
+}
+.leaflet-marker-pane {
+  z-index: 600;
+}
+.leaflet-popup-pane {
+  z-index: 700;
+}
+.leaflet-map-pane canvas {
+  z-index: 100;
+}
+.leaflet-map-pane svg {
+  z-index: 200;
+}
+.leaflet-vml-shape {
+  width: 1px;
+  height: 1px;
+}
+.lvml {
+  behavior: url(#default#VML);
+  display: inline-block;
+  position: absolute;
+}
+/* control positioning */
+.leaflet-control {
+  position: relative;
+  z-index: 800;
+  pointer-events: auto;
+}
+.leaflet-top,
+.leaflet-bottom {
+  position: absolute;
+  z-index: 1000;
+  pointer-events: none;
+}
+.leaflet-top {
+  top: 0;
+}
+.leaflet-right {
+  right: 0;
+}
+.leaflet-bottom {
+  bottom: 0;
+}
+.leaflet-left {
+  left: 0;
+}
+.leaflet-control {
+  float: left;
+  clear: both;
+}
+.leaflet-right .leaflet-control {
+  float: right;
+}
+.leaflet-top .leaflet-control {
+  margin-top: 10px;
+}
+.leaflet-bottom .leaflet-control {
+  margin-bottom: 10px;
+}
+.leaflet-left .leaflet-control {
+  margin-left: 10px;
+}
+.leaflet-right .leaflet-control {
+  margin-right: 10px;
+}
+/* zoom and fade animations */
+.leaflet-fade-anim .leaflet-tile {
+  will-change: opacity;
+}
+.leaflet-fade-anim .leaflet-popup {
+  opacity: 0;
+  -webkit-transition: opacity 0.2s linear;
+  -moz-transition: opacity 0.2s linear;
+  -o-transition: opacity 0.2s linear;
+  transition: opacity 0.2s linear;
+}
+.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
+  opacity: 1;
+}
+.leaflet-zoom-animated {
+  -webkit-transform-origin: 0 0;
+  -ms-transform-origin: 0 0;
+  transform-origin: 0 0;
+}
+.leaflet-zoom-anim .leaflet-zoom-animated {
+  will-change: transform;
+}
+.leaflet-zoom-anim .leaflet-zoom-animated {
+  -webkit-transition: -webkit-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
+  -moz-transition: -moz-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
+  -o-transition: -o-transform 0.25s cubic-bezier(0, 0, 0.25, 1);
+  transition: transform 0.25s cubic-bezier(0, 0, 0.25, 1);
+}
+.leaflet-zoom-anim .leaflet-tile,
+.leaflet-pan-anim .leaflet-tile {
+  -webkit-transition: none;
+  -moz-transition: none;
+  -o-transition: none;
+  transition: none;
+}
+.leaflet-zoom-anim .leaflet-zoom-hide {
+  visibility: hidden;
+}
+/* cursors */
+.leaflet-interactive {
+  cursor: pointer;
+}
+.leaflet-grab {
+  cursor: -webkit-grab;
+  cursor: -moz-grab;
+}
+.leaflet-crosshair,
+.leaflet-crosshair .leaflet-interactive {
+  cursor: crosshair;
+}
+.leaflet-popup-pane,
+.leaflet-control {
+  cursor: auto;
+}
+.leaflet-dragging .leaflet-grab,
+.leaflet-dragging .leaflet-grab .leaflet-interactive,
+.leaflet-dragging .leaflet-marker-draggable {
+  cursor: move;
+  cursor: -webkit-grabbing;
+  cursor: -moz-grabbing;
+}
+/* marker & overlays interactivity */
+.leaflet-marker-icon,
+.leaflet-marker-shadow,
+.leaflet-image-layer,
+.leaflet-pane > svg path,
+.leaflet-tile-container {
+  pointer-events: none;
+}
+.leaflet-marker-icon.leaflet-interactive,
+.leaflet-image-layer.leaflet-interactive,
+.leaflet-pane > svg path.leaflet-interactive {
+  pointer-events: auto;
+}
+/* visual tweaks */
+.leaflet-container {
+  /*background: #ddd;*/
+  outline: 0;
+}
+.leaflet-container a {
+  color: #0078A8;
+}
+.leaflet-container a.leaflet-active {
+  outline: 2px solid orange;
+}
+.leaflet-zoom-box {
+  border: 2px dotted #38f;
+  background: rgba(255, 255, 255, 0.5);
+}
+/* general typography */
+.leaflet-container {
+  font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
+}
+/* general toolbar styles */
+.leaflet-bar {
+  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
+  border-radius: 4px;
+}
+.leaflet-bar a,
+.leaflet-bar a:hover {
+  background-color: #fff;
+  border-bottom: 1px solid #ccc;
+  width: 26px;
+  height: 26px;
+  line-height: 26px;
+  display: block;
+  text-align: center;
+  text-decoration: none;
+  color: black;
+}
+.leaflet-bar a,
+.leaflet-control-layers-toggle {
+  background-position: 50% 50%;
+  background-repeat: no-repeat;
+  display: block;
+}
+.leaflet-bar a:hover {
+  background-color: #f4f4f4;
+}
+.leaflet-bar a:first-child {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+.leaflet-bar a:last-child {
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+  border-bottom: none;
+}
+.leaflet-bar a.leaflet-disabled {
+  cursor: default;
+  background-color: #f4f4f4;
+  color: #bbb;
+}
+.leaflet-touch .leaflet-bar a {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+/* zoom control */
+.leaflet-control-zoom-in,
+.leaflet-control-zoom-out {
+  font: bold 18px 'Lucida Console', Monaco, monospace;
+  text-indent: 1px;
+}
+.leaflet-control-zoom-out {
+  font-size: 20px;
+}
+.leaflet-touch .leaflet-control-zoom-in {
+  font-size: 22px;
+}
+.leaflet-touch .leaflet-control-zoom-out {
+  font-size: 24px;
+}
+/* layers control */
+.leaflet-control-layers {
+  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
+  background: #fff;
+  border-radius: 5px;
+}
+.leaflet-control-layers-toggle {
+  background-image: url(images/layers.png);
+  width: 36px;
+  height: 36px;
+}
+.leaflet-retina .leaflet-control-layers-toggle {
+  background-image: url(images/layers-2x.png);
+  background-size: 26px 26px;
+}
+.leaflet-touch .leaflet-control-layers-toggle {
+  width: 44px;
+  height: 44px;
+}
+.leaflet-control-layers .leaflet-control-layers-list,
+.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
+  display: none;
+}
+.leaflet-control-layers-expanded .leaflet-control-layers-list {
+  display: block;
+  position: relative;
+}
+.leaflet-control-layers-expanded {
+  padding: 6px 10px 6px 6px;
+  color: #333;
+  background: #fff;
+}
+.leaflet-control-layers-scrollbar {
+  overflow-y: scroll;
+  padding-right: 5px;
+}
+.leaflet-control-layers-selector {
+  margin-top: 2px;
+  position: relative;
+  top: 1px;
+}
+.leaflet-control-layers label {
+  display: block;
+}
+.leaflet-control-layers-separator {
+  height: 0;
+  border-top: 1px solid #ddd;
+  margin: 5px -10px 5px -6px;
+}
+/* attribution and scale controls */
+.leaflet-container .leaflet-control-attribution {
+  background: #fff;
+  background: rgba(255, 255, 255, 0.7);
+  margin: 0;
+}
+.leaflet-control-attribution,
+.leaflet-control-scale-line {
+  padding: 0 5px;
+  color: #333;
+}
+.leaflet-control-attribution a {
+  text-decoration: none;
+}
+.leaflet-control-attribution a:hover {
+  text-decoration: underline;
+}
+.leaflet-container .leaflet-control-attribution,
+.leaflet-container .leaflet-control-scale {
+  font-size: 11px;
+}
+.leaflet-left .leaflet-control-scale {
+  margin-left: 5px;
+}
+.leaflet-bottom .leaflet-control-scale {
+  margin-bottom: 5px;
+}
+.leaflet-control-scale-line {
+  border: 2px solid #777;
+  border-top: none;
+  line-height: 1.1;
+  padding: 2px 5px 1px;
+  font-size: 11px;
+  white-space: nowrap;
+  overflow: hidden;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  background: #fff;
+  background: rgba(255, 255, 255, 0.5);
+}
+.leaflet-control-scale-line:not(:first-child) {
+  border-top: 2px solid #777;
+  border-bottom: none;
+  margin-top: -2px;
+}
+.leaflet-control-scale-line:not(:first-child):not(:last-child) {
+  border-bottom: 2px solid #777;
+}
+.leaflet-touch .leaflet-control-attribution,
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+  box-shadow: none;
+}
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+  border: 2px solid rgba(0, 0, 0, 0.2);
+  background-clip: padding-box;
+}
+/* popup */
+.leaflet-popup {
+  position: absolute;
+  text-align: center;
+}
+.leaflet-popup-content-wrapper {
+  padding: 1px;
+  text-align: left;
+  border-radius: 12px;
+}
+.leaflet-popup-content {
+  margin: 13px 19px;
+  line-height: 1.4;
+}
+.leaflet-popup-content p {
+  margin: 18px 0;
+}
+.leaflet-popup-tip-container {
+  margin: 0 auto;
+  width: 40px;
+  height: 20px;
+  position: relative;
+  overflow: hidden;
+}
+.leaflet-popup-tip {
+  width: 17px;
+  height: 17px;
+  padding: 1px;
+  margin: -10px auto 0;
+  -webkit-transform: rotate(45deg);
+  -moz-transform: rotate(45deg);
+  -ms-transform: rotate(45deg);
+  -o-transform: rotate(45deg);
+  transform: rotate(45deg);
+}
+.leaflet-popup-content-wrapper,
+.leaflet-popup-tip {
+  background: white;
+  color: #333;
+  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
+}
+.leaflet-container a.leaflet-popup-close-button {
+  position: absolute;
+  top: 0;
+  right: 0;
+  padding: 4px 4px 0 0;
+  border: none;
+  text-align: center;
+  width: 18px;
+  height: 14px;
+  font: 16px/14px Tahoma, Verdana, sans-serif;
+  color: #c3c3c3;
+  text-decoration: none;
+  font-weight: bold;
+  background: transparent;
+}
+.leaflet-container a.leaflet-popup-close-button:hover {
+  color: #999;
+}
+.leaflet-popup-scrolled {
+  overflow: auto;
+  border-bottom: 1px solid #ddd;
+  border-top: 1px solid #ddd;
+}
+.leaflet-oldie .leaflet-popup-content-wrapper {
+  zoom: 1;
+}
+.leaflet-oldie .leaflet-popup-tip {
+  width: 24px;
+  margin: 0 auto;
+  -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
+  filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
+}
+.leaflet-oldie .leaflet-popup-tip-container {
+  margin-top: -1px;
+}
+.leaflet-oldie .leaflet-control-zoom,
+.leaflet-oldie .leaflet-control-layers,
+.leaflet-oldie .leaflet-popup-content-wrapper,
+.leaflet-oldie .leaflet-popup-tip {
+  border: 1px solid #999;
+}
+/* div icon */
+.leaflet-div-icon {
+  background: #fff;
+  border: 1px solid #666;
+}
+/*-------------------------------------
+zTree Style
+
+version:	3.5.17
+author:		Hunter.z
+email:		hunter.z@263.net
+website:	http://code.google.com/p/jquerytree/
+
+-------------------------------------*/
+.ztree * {
+  padding: 0;
+  margin: 0;
+  font-size: 12px;
+  font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif;
+}
+.ztree {
+  margin: 0;
+  padding: 5px;
+  color: #333333;
+}
+.ztree li {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+  line-height: 14px;
+  text-align: left;
+  white-space: nowrap;
+  outline: 0;
+}
+.ztree li ul {
+  margin: 0;
+  padding: 0 0 0 18px;
+}
+.ztree li ul.line {
+  background: url(icon/tree-vertical-line-1.png) 0 0 repeat-y;
+}
+.ztree li a {
+  padding: 1px 3px 0 0;
+  margin: 0;
+  cursor: pointer;
+  height: 24px;
+  color: #333;
+  background-color: transparent;
+  text-decoration: none;
+  vertical-align: top;
+  display: inline-block;
+}
+.ztree li a.curSelectedNode_Edit {
+  padding-top: 0px;
+  background-color: #FFE6B0;
+  color: black;
+  height: 16px;
+  border: 1px #FFB951 solid;
+  opacity: 0.8;
+}
+.ztree li a.tmpTargetNode_inner {
+  padding-top: 0px;
+  background-color: #316AC5;
+  color: white;
+  height: 16px;
+  border: 1px #316AC5 solid;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+.ztree li a input.rename {
+  height: 14px;
+  width: 80px;
+  padding: 0;
+  margin: 0;
+  font-size: 12px;
+  border: 1px #7EC4CC solid;
+  *border: 0px;
+}
+.ztree li span {
+  line-height: 24px;
+  margin-right: 2px;
+}
+.ztree li span.button {
+  line-height: 0;
+  margin: 0;
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+  vertical-align: middle;
+  border: 0 none;
+  cursor: pointer;
+  outline: none;
+  background-color: transparent;
+  background-repeat: no-repeat;
+  background-attachment: scroll;
+  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/zTreeStandard.png");
+  *background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/zTreeStandard.gif");
+}
+.ztree li span.button.chk {
+  width: 16px;
+  height: 16px;
+  margin: 0 3px 0 0;
+  cursor: auto;
+}
+.ztree li span.button.chk.checkbox_false_full {
+  background-image: url("icon/check-box-normal.png");
+}
+.ztree li span.button.chk.checkbox_false_full_focus {
+  background-image: url("icon/check-box-normal.png");
+}
+.ztree li span.button.chk.checkbox_false_part {
+  background-image: url("icon/half_selected.png");
+}
+.ztree li span.button.chk.checkbox_false_part_focus {
+  background-image: url("icon/half_selected.png");
+}
+.ztree li span.button.chk.checkbox_false_disable {
+  background-position: 0 -56px;
+}
+.ztree li span.button.chk.checkbox_true_full {
+  background-image: url("icon/check-box-active.png");
+}
+.ztree li span.button.chk.checkbox_true_full_focus {
+  background-image: url("icon/check-box-active.png");
+}
+.ztree li span.button.chk.checkbox_true_part {
+  background-image: url("icon/half_selected.png");
+}
+.ztree li span.button.chk.checkbox_true_part_focus {
+  background-image: url("icon/half_selected.png");
+}
+.ztree li span.button.chk.checkbox_true_disable {
+  background-position: -14px -56px;
+}
+.ztree li span.button.chk.radio_false_full {
+  background-position: -28px 0;
+}
+.ztree li span.button.chk.radio_false_full_focus {
+  background-position: -28px -14px;
+}
+.ztree li span.button.chk.radio_false_part {
+  background-position: -28px -28px;
+}
+.ztree li span.button.chk.radio_false_part_focus {
+  background-position: -28px -42px;
+}
+.ztree li span.button.chk.radio_false_disable {
+  background-position: -28px -56px;
+}
+.ztree li span.button.chk.radio_true_full {
+  background-position: -42px 0;
+}
+.ztree li span.button.chk.radio_true_full_focus {
+  background-position: -42px -14px;
+}
+.ztree li span.button.chk.radio_true_part {
+  background-position: -42px -28px;
+}
+.ztree li span.button.chk.radio_true_part_focus {
+  background-position: -42px -42px;
+}
+.ztree li span.button.chk.radio_true_disable {
+  background-position: -42px -56px;
+}
+.ztree li span.button.switch {
+  width: 25px;
+  height: 25px;
+}
+.ztree li span.button.root_open {
+  background-image: url("icon/tree-expand-1.png");
+}
+.ztree li span.button.root_close {
+  background-image: url("icon/tree-collapse-1.png");
+}
+.ztree li span.button.roots_open {
+  background-image: url("icon/tree-expand-2.png");
+}
+.ztree li span.button.roots_close {
+  background-image: url("icon/tree-collapse-2.png");
+}
+.ztree li span.button.center_open {
+  background-image: url("icon/tree-expand-3.png");
+}
+.ztree li span.button.center_close {
+  background-image: url("icon/tree-collapse-3.png");
+}
+.ztree li span.button.bottom_open {
+  background-image: url("icon/tree-expand-4.png");
+}
+.ztree li span.button.bottom_close {
+  background-image: url("icon/tree-collapse-4.png");
+}
+.ztree li span.button.noline_open {
+  background-position: -92px -72px;
+}
+.ztree li span.button.noline_close {
+  background-position: -74px -72px;
+}
+.ztree li span.button.root_docu {
+  background: none;
+}
+.ztree li span.button.roots_docu {
+  background-image: url("icon/tree-vertical-line-2.png");
+}
+.ztree li span.button.center_docu {
+  background-image: url("icon/tree-vertical-line-3.png");
+}
+.ztree li span.button.bottom_docu {
+  background-image: url("icon/tree-vertical-line-4.png");
+}
+.ztree li span.button.noline_docu {
+  background: none;
+}
+.ztree li span.button.ico_open {
+  margin-right: 2px;
+  background-position: -110px -16px;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+.ztree li span.button.ico_close {
+  margin-right: 2px;
+  background-position: -110px 0;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+.ztree li span.button.ico_docu {
+  margin-right: 2px;
+  background-position: -110px -32px;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+.ztree li span.button.edit {
+  margin-right: 2px;
+  background-position: -110px -48px;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+.ztree li span.button.remove {
+  margin-right: 2px;
+  background-position: -110px -64px;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+.ztree li span.button.ico_loading {
+  width: 0px;
+  margin-right: 2px;
+  background: url("${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/loading.gif") no-repeat scroll 0 0 transparent;
+  vertical-align: top;
+  *vertical-align: middle;
+}
+ul.tmpTargetzTree {
+  background-color: #FFE6B0;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+span.tmpzTreeMove_arrow {
+  width: 16px;
+  height: 16px;
+  display: inline-block;
+  padding: 0;
+  margin: 2px 0 0 1px;
+  border: 0 none;
+  position: absolute;
+  background-color: transparent;
+  background-repeat: no-repeat;
+  background-attachment: scroll;
+  background-position: -110px -80px;
+  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/zTreeStandard.png");
+  *background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/zTreeStandard.gif");
+}
+ul.ztree.zTreeDragUL {
+  margin: 0;
+  padding: 0;
+  position: absolute;
+  width: auto;
+  height: auto;
+  overflow: hidden;
+  background-color: #cfcfcf;
+  border: 1px #00B83F dotted;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+.zTreeMask {
+  z-index: 10000;
+  background-color: #cfcfcf;
+  opacity: 0.0;
+  filter: alpha(opacity=0);
+  position: absolute;
+}
+/* level style*/
+/*.ztree li span.button.level0 {
+	display:none;
+}
+.ztree li ul.level0 {
+	padding:0;
+	background:none;
+}*/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-branch-tree .bi-branch-tree-view {
+  min-width: 300px;
+}
+.bi-click-branch-tree {
+  border: 1px solid #d4dadd;
+}
+.bi-click-branch-tree .bi-empty-view {
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-display-tree .ztree * {
+  color: #808080;
+}
+.bi-display-tree .ztree li span.button.switch.center_open {
+  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png");
+}
+.bi-display-tree .ztree li span.button.switch.roots_open {
+  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png");
+}
+.bi-display-tree .ztree li span.button.switch.bottom_open {
+  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png");
+}
+.bi-display-tree .ztree li a,
+.bi-display-tree .ztree li span {
+  cursor: default !important;
+}
+.bi-display-tree .ztree li a:hover {
+  text-decoration: none;
+}
+.bi-display-tree .ztree li a.curSelectedNode {
+  padding-top: 1px;
+  border: none;
+  background-color: inherit;
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-trigger .bi-trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-editor-trigger {
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-text-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-small-select-text-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-float-box {
+  background: #ffffff;
+}
+.bi-float-box .float-box-button {
+  color: #ffffff;
+  background: #009de3;
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/**********FR.BIListView*************/
+.bi-list-view {
+  position: fixed !important;
+  overflow-y: visible !important;
+  overflow-x: visible !important;
+  overflow: visible !important;
+  cursor: default;
+}
+.bi-list-view .list-view-outer {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #ffffff;
+}
+.bi-list-view .list-view-toolbar {
+  border-top: 1px solid #eaeaea;
+  line-height: 30px;
+  color: #009de3;
+}
+.bi-list-view .list-view-toolbar > .center-element {
+  border-left: 1px solid #eaeaea;
+}
+.bi-list-view .list-view-toolbar > .first-element {
+  border-left: none;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-scroll-view .scroll-container {
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-scroll-view .scroll-drop-down-icon {
+  font-size: 14px;
+  border-bottom: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  background: #f4f4f4;
+}
+.bi-scroll-view .scroll-drop-down-icon:active {
+  background: #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-inline-center-adapt-layout:after {
+  display: inline-block;
+  width: 0;
+  min-height: 100%;
+  vertical-align: middle;
+  content: ' ';
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-inline-vertical-adapt-layout:after {
+  display: inline-block;
+  width: 0;
+  min-height: 100%;
+  vertical-align: middle;
+  content: ' ';
+}
diff --git a/dist/base.js b/dist/base.js
new file mode 100644
index 000000000..0cb0dd97e
--- /dev/null
+++ b/dist/base.js
@@ -0,0 +1,35151 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// This is CodeMirror (http://codemirror.net), a code editor
+// implemented in JavaScript on top of the browser's DOM.
+//
+// You can find some technical background for some of the code below
+// at http://marijnhaverbeke.nl/blog/#cm-internals .
+
+(function(mod) {
+    this.CodeMirror = mod();
+})(function() {
+  "use strict";
+
+  // BROWSER SNIFFING
+
+  // Kludges for bugs and behavior differences that can't be feature
+  // detected are enabled based on userAgent etc sniffing.
+
+  var gecko = /gecko\/\d/i.test(navigator.userAgent);
+  var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
+  var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
+  var ie = ie_upto10 || ie_11up;
+  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
+  var webkit = /WebKit\//.test(navigator.userAgent);
+  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
+  var chrome = /Chrome\//.test(navigator.userAgent);
+  var presto = /Opera\//.test(navigator.userAgent);
+  var safari = /Apple Computer/.test(navigator.vendor);
+  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
+  var phantom = /PhantomJS/.test(navigator.userAgent);
+
+  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+  // This is woefully incomplete. Suggestions for alternative methods welcome.
+  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
+  var mac = ios || /Mac/.test(navigator.platform);
+  var windows = /win/i.test(navigator.platform);
+
+  var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+  if (presto_version) presto_version = Number(presto_version[1]);
+  if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
+  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
+  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
+  var captureRightClick = gecko || (ie && ie_version >= 9);
+
+  // Optimize some code when these features are not used.
+  var sawReadOnlySpans = false, sawCollapsedSpans = false;
+
+  // EDITOR CONSTRUCTOR
+
+  // A CodeMirror instance represents an editor. This is the object
+  // that user code is usually dealing with.
+
+  function CodeMirror(place, options) {
+    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
+
+    this.options = options = options ? copyObj(options) : {};
+    // Determine effective options based on given values and defaults.
+    copyObj(defaults, options, false);
+    setGuttersForLineNumbers(options);
+
+    var doc = options.value;
+    if (typeof doc == "string") doc = new Doc(doc, options.mode);
+    this.doc = doc;
+
+    var input = new CodeMirror.inputStyles[options.inputStyle](this);
+    var display = this.display = new Display(place, doc, input);
+    display.wrapper.CodeMirror = this;
+    updateGutters(this);
+    themeChanged(this);
+    if (options.lineWrapping)
+      this.display.wrapper.className += " CodeMirror-wrap";
+    if (options.autofocus && !mobile) display.input.focus();
+    initScrollbars(this);
+
+    this.state = {
+      keyMaps: [],  // stores maps added by addKeyMap
+      overlays: [], // highlighting overlays, as added by addOverlay
+      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
+      overwrite: false,
+      delayingBlurEvent: false,
+      focused: false,
+      suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
+      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
+      draggingText: false,
+      highlight: new Delayed(), // stores highlight worker timeout
+      keySeq: null,  // Unfinished key sequence
+      specialChars: null
+    };
+
+    var cm = this;
+
+    // Override magic textarea content restore that IE sometimes does
+    // on our hidden textarea on reload
+    if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
+
+    registerEventHandlers(this);
+    ensureGlobalHandlers();
+
+    startOperation(this);
+    this.curOp.forceUpdate = true;
+    attachDoc(this, doc);
+
+    if ((options.autofocus && !mobile) || cm.hasFocus())
+      setTimeout(bind(onFocus, this), 20);
+    else
+      onBlur(this);
+
+    for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
+      optionHandlers[opt](this, options[opt], Init);
+    maybeUpdateLineNumberWidth(this);
+    if (options.finishInit) options.finishInit(this);
+    for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
+    endOperation(this);
+    // Suppress optimizelegibility in Webkit, since it breaks text
+    // measuring on line wrapping boundaries.
+    if (webkit && options.lineWrapping &&
+        getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
+      display.lineDiv.style.textRendering = "auto";
+  }
+
+  // DISPLAY CONSTRUCTOR
+
+  // The display handles the DOM integration, both for input reading
+  // and content drawing. It holds references to DOM nodes and
+  // display-related state.
+
+  function Display(place, doc, input) {
+    var d = this;
+    this.input = input;
+
+    // Covers bottom-right square when both scrollbars are present.
+    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
+    d.scrollbarFiller.setAttribute("cm-not-content", "true");
+    // Covers bottom of gutter when coverGutterNextToScrollbar is on
+    // and h scrollbar is present.
+    d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
+    d.gutterFiller.setAttribute("cm-not-content", "true");
+    // Will contain the actual code, positioned to cover the viewport.
+    d.lineDiv = elt("div", null, "CodeMirror-code");
+    // Elements are added to these to represent selection and cursors.
+    d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
+    d.cursorDiv = elt("div", null, "CodeMirror-cursors");
+    // A visibility: hidden element used to find the size of things.
+    d.measure = elt("div", null, "CodeMirror-measure");
+    // When lines outside of the viewport are measured, they are drawn in this.
+    d.lineMeasure = elt("div", null, "CodeMirror-measure");
+    // Wraps everything that needs to exist inside the vertically-padded coordinate system
+    d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
+                      null, "position: relative; outline: none");
+    // Moved around its parent to cover visible view.
+    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
+    // Set to the height of the document, allowing scrolling.
+    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
+    d.sizerWidth = null;
+    // Behavior of elts with overflow: auto and padding is
+    // inconsistent across browsers. This is used to ensure the
+    // scrollable area is big enough.
+    d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
+    // Will contain the gutters, if any.
+    d.gutters = elt("div", null, "CodeMirror-gutters");
+    d.lineGutter = null;
+    // Actual scrollable element.
+    d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
+    d.scroller.setAttribute("tabIndex", "-1");
+    // The element in which the editor lives.
+    d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
+
+    // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
+    if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
+    if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
+
+    if (place) {
+      if (place.appendChild) place.appendChild(d.wrapper);
+      else place(d.wrapper);
+    }
+
+    // Current rendered range (may be bigger than the view window).
+    d.viewFrom = d.viewTo = doc.first;
+    d.reportedViewFrom = d.reportedViewTo = doc.first;
+    // Information about the rendered lines.
+    d.view = [];
+    d.renderedView = null;
+    // Holds info about a single rendered line when it was rendered
+    // for measurement, while not in view.
+    d.externalMeasured = null;
+    // Empty space (in pixels) above the view
+    d.viewOffset = 0;
+    d.lastWrapHeight = d.lastWrapWidth = 0;
+    d.updateLineNumbers = null;
+
+    d.nativeBarWidth = d.barHeight = d.barWidth = 0;
+    d.scrollbarsClipped = false;
+
+    // Used to only resize the line number gutter when necessary (when
+    // the amount of lines crosses a boundary that makes its width change)
+    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
+    // Set to true when a non-horizontal-scrolling line widget is
+    // added. As an optimization, line widget aligning is skipped when
+    // this is false.
+    d.alignWidgets = false;
+
+    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+
+    // Tracks the maximum line length so that the horizontal scrollbar
+    // can be kept static when scrolling.
+    d.maxLine = null;
+    d.maxLineLength = 0;
+    d.maxLineChanged = false;
+
+    // Used for measuring wheel scrolling granularity
+    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
+
+    // True when shift is held down.
+    d.shift = false;
+
+    // Used to track whether anything happened since the context menu
+    // was opened.
+    d.selForContextMenu = null;
+
+    d.activeTouch = null;
+
+    input.init(d);
+  }
+
+  // STATE UPDATES
+
+  // Used to get the editor into a consistent state again when options change.
+
+  function loadMode(cm) {
+    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
+    resetModeState(cm);
+  }
+
+  function resetModeState(cm) {
+    cm.doc.iter(function(line) {
+      if (line.stateAfter) line.stateAfter = null;
+      if (line.styles) line.styles = null;
+    });
+    cm.doc.frontier = cm.doc.first;
+    startWorker(cm, 100);
+    cm.state.modeGen++;
+    if (cm.curOp) regChange(cm);
+  }
+
+  function wrappingChanged(cm) {
+    if (cm.options.lineWrapping) {
+      addClass(cm.display.wrapper, "CodeMirror-wrap");
+      cm.display.sizer.style.minWidth = "";
+      cm.display.sizerWidth = null;
+    } else {
+      rmClass(cm.display.wrapper, "CodeMirror-wrap");
+      findMaxLine(cm);
+    }
+    estimateLineHeights(cm);
+    regChange(cm);
+    clearCaches(cm);
+    setTimeout(function(){updateScrollbars(cm);}, 100);
+  }
+
+  // Returns a function that estimates the height of a line, to use as
+  // first approximation until the line becomes visible (and is thus
+  // properly measurable).
+  function estimateHeight(cm) {
+    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
+    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
+    return function(line) {
+      if (lineIsHidden(cm.doc, line)) return 0;
+
+      var widgetsHeight = 0;
+      if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
+        if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
+      }
+
+      if (wrapping)
+        return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
+      else
+        return widgetsHeight + th;
+    };
+  }
+
+  function estimateLineHeights(cm) {
+    var doc = cm.doc, est = estimateHeight(cm);
+    doc.iter(function(line) {
+      var estHeight = est(line);
+      if (estHeight != line.height) updateLineHeight(line, estHeight);
+    });
+  }
+
+  function themeChanged(cm) {
+    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
+      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+    clearCaches(cm);
+  }
+
+  function guttersChanged(cm) {
+    updateGutters(cm);
+    regChange(cm);
+    setTimeout(function(){alignHorizontally(cm);}, 20);
+  }
+
+  // Rebuild the gutter elements, ensure the margin to the left of the
+  // code matches their width.
+  function updateGutters(cm) {
+    var gutters = cm.display.gutters, specs = cm.options.gutters;
+    removeChildren(gutters);
+    for (var i = 0; i < specs.length; ++i) {
+      var gutterClass = specs[i];
+      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
+      if (gutterClass == "CodeMirror-linenumbers") {
+        cm.display.lineGutter = gElt;
+        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
+      }
+    }
+    gutters.style.display = i ? "" : "none";
+    updateGutterSpace(cm);
+  }
+
+  function updateGutterSpace(cm) {
+    var width = cm.display.gutters.offsetWidth;
+    cm.display.sizer.style.marginLeft = width + "px";
+  }
+
+  // Compute the character length of a line, taking into account
+  // collapsed ranges (see markText) that might hide parts, and join
+  // other lines onto it.
+  function lineLength(line) {
+    if (line.height == 0) return 0;
+    var len = line.text.length, merged, cur = line;
+    while (merged = collapsedSpanAtStart(cur)) {
+      var found = merged.find(0, true);
+      cur = found.from.line;
+      len += found.from.ch - found.to.ch;
+    }
+    cur = line;
+    while (merged = collapsedSpanAtEnd(cur)) {
+      var found = merged.find(0, true);
+      len -= cur.text.length - found.from.ch;
+      cur = found.to.line;
+      len += cur.text.length - found.to.ch;
+    }
+    return len;
+  }
+
+  // Find the longest line in the document.
+  function findMaxLine(cm) {
+    var d = cm.display, doc = cm.doc;
+    d.maxLine = getLine(doc, doc.first);
+    d.maxLineLength = lineLength(d.maxLine);
+    d.maxLineChanged = true;
+    doc.iter(function(line) {
+      var len = lineLength(line);
+      if (len > d.maxLineLength) {
+        d.maxLineLength = len;
+        d.maxLine = line;
+      }
+    });
+  }
+
+  // Make sure the gutters options contains the element
+  // "CodeMirror-linenumbers" when the lineNumbers option is true.
+  function setGuttersForLineNumbers(options) {
+    var found = indexOf(options.gutters, "CodeMirror-linenumbers");
+    if (found == -1 && options.lineNumbers) {
+      options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
+    } else if (found > -1 && !options.lineNumbers) {
+      options.gutters = options.gutters.slice(0);
+      options.gutters.splice(found, 1);
+    }
+  }
+
+  // SCROLLBARS
+
+  // Prepare DOM reads needed to update the scrollbars. Done in one
+  // shot to minimize update/measure roundtrips.
+  function measureForScrollbars(cm) {
+    var d = cm.display, gutterW = d.gutters.offsetWidth;
+    var docH = Math.round(cm.doc.height + paddingVert(cm.display));
+    return {
+      clientHeight: d.scroller.clientHeight,
+      viewHeight: d.wrapper.clientHeight,
+      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
+      viewWidth: d.wrapper.clientWidth,
+      barLeft: cm.options.fixedGutter ? gutterW : 0,
+      docHeight: docH,
+      scrollHeight: docH + scrollGap(cm) + d.barHeight,
+      nativeBarWidth: d.nativeBarWidth,
+      gutterWidth: gutterW
+    };
+  }
+
+  function NativeScrollbars(place, scroll, cm) {
+    this.cm = cm;
+    var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
+    var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
+    place(vert); place(horiz);
+
+    on(vert, "scroll", function() {
+      if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
+    });
+    on(horiz, "scroll", function() {
+      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
+    });
+
+    this.checkedOverlay = false;
+    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
+  }
+
+  NativeScrollbars.prototype = copyObj({
+    update: function(measure) {
+      var needsH = measure.scrollWidth > measure.clientWidth + 1;
+      var needsV = measure.scrollHeight > measure.clientHeight + 1;
+      var sWidth = measure.nativeBarWidth;
+
+      if (needsV) {
+        this.vert.style.display = "block";
+        this.vert.style.bottom = needsH ? sWidth + "px" : "0";
+        var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
+        // A bug in IE8 can cause this value to be negative, so guard it.
+        this.vert.firstChild.style.height =
+          Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
+      } else {
+        this.vert.style.display = "";
+        this.vert.firstChild.style.height = "0";
+      }
+
+      if (needsH) {
+        this.horiz.style.display = "block";
+        this.horiz.style.right = needsV ? sWidth + "px" : "0";
+        this.horiz.style.left = measure.barLeft + "px";
+        var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
+        this.horiz.firstChild.style.width =
+          (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
+      } else {
+        this.horiz.style.display = "";
+        this.horiz.firstChild.style.width = "0";
+      }
+
+      if (!this.checkedOverlay && measure.clientHeight > 0) {
+        if (sWidth == 0) this.overlayHack();
+        this.checkedOverlay = true;
+      }
+
+      return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
+    },
+    setScrollLeft: function(pos) {
+      if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
+    },
+    setScrollTop: function(pos) {
+      if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
+    },
+    overlayHack: function() {
+      var w = mac && !mac_geMountainLion ? "12px" : "18px";
+      this.horiz.style.minHeight = this.vert.style.minWidth = w;
+      var self = this;
+      var barMouseDown = function(e) {
+        if (e_target(e) != self.vert && e_target(e) != self.horiz)
+          operation(self.cm, onMouseDown)(e);
+      };
+      on(this.vert, "mousedown", barMouseDown);
+      on(this.horiz, "mousedown", barMouseDown);
+    },
+    clear: function() {
+      var parent = this.horiz.parentNode;
+      parent.removeChild(this.horiz);
+      parent.removeChild(this.vert);
+    }
+  }, NativeScrollbars.prototype);
+
+  function NullScrollbars() {}
+
+  NullScrollbars.prototype = copyObj({
+    update: function() { return {bottom: 0, right: 0}; },
+    setScrollLeft: function() {},
+    setScrollTop: function() {},
+    clear: function() {}
+  }, NullScrollbars.prototype);
+
+  CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
+
+  function initScrollbars(cm) {
+    if (cm.display.scrollbars) {
+      cm.display.scrollbars.clear();
+      if (cm.display.scrollbars.addClass)
+        rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+    }
+
+    cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
+      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
+      // Prevent clicks in the scrollbars from killing focus
+      on(node, "mousedown", function() {
+        if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
+      });
+      node.setAttribute("cm-not-content", "true");
+    }, function(pos, axis) {
+      if (axis == "horizontal") setScrollLeft(cm, pos);
+      else setScrollTop(cm, pos);
+    }, cm);
+    if (cm.display.scrollbars.addClass)
+      addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+  }
+
+  function updateScrollbars(cm, measure) {
+    if (!measure) measure = measureForScrollbars(cm);
+    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
+    updateScrollbarsInner(cm, measure);
+    for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
+      if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
+        updateHeightsInViewport(cm);
+      updateScrollbarsInner(cm, measureForScrollbars(cm));
+      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
+    }
+  }
+
+  // Re-synchronize the fake scrollbars with the actual size of the
+  // content.
+  function updateScrollbarsInner(cm, measure) {
+    var d = cm.display;
+    var sizes = d.scrollbars.update(measure);
+
+    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
+    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
+
+    if (sizes.right && sizes.bottom) {
+      d.scrollbarFiller.style.display = "block";
+      d.scrollbarFiller.style.height = sizes.bottom + "px";
+      d.scrollbarFiller.style.width = sizes.right + "px";
+    } else d.scrollbarFiller.style.display = "";
+    if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
+      d.gutterFiller.style.display = "block";
+      d.gutterFiller.style.height = sizes.bottom + "px";
+      d.gutterFiller.style.width = measure.gutterWidth + "px";
+    } else d.gutterFiller.style.display = "";
+  }
+
+  // Compute the lines that are visible in a given viewport (defaults
+  // the the current scroll position). viewport may contain top,
+  // height, and ensure (see op.scrollToPos) properties.
+  function visibleLines(display, doc, viewport) {
+    var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
+    top = Math.floor(top - paddingTop(display));
+    var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
+
+    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
+    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
+    // forces those lines into the viewport (if possible).
+    if (viewport && viewport.ensure) {
+      var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
+      if (ensureFrom < from) {
+        from = ensureFrom;
+        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
+      } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
+        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
+        to = ensureTo;
+      }
+    }
+    return {from: from, to: Math.max(to, from + 1)};
+  }
+
+  // LINE NUMBERS
+
+  // Re-align line numbers and gutter marks to compensate for
+  // horizontal scrolling.
+  function alignHorizontally(cm) {
+    var display = cm.display, view = display.view;
+    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
+    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
+    var gutterW = display.gutters.offsetWidth, left = comp + "px";
+    for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
+      if (cm.options.fixedGutter && view[i].gutter)
+        view[i].gutter.style.left = left;
+      var align = view[i].alignable;
+      if (align) for (var j = 0; j < align.length; j++)
+        align[j].style.left = left;
+    }
+    if (cm.options.fixedGutter)
+      display.gutters.style.left = (comp + gutterW) + "px";
+  }
+
+  // Used to ensure that the line number gutter is still the right
+  // size for the current document size. Returns true when an update
+  // is needed.
+  function maybeUpdateLineNumberWidth(cm) {
+    if (!cm.options.lineNumbers) return false;
+    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
+    if (last.length != display.lineNumChars) {
+      var test = display.measure.appendChild(elt("div", [elt("div", last)],
+                                                 "CodeMirror-linenumber CodeMirror-gutter-elt"));
+      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
+      display.lineGutter.style.width = "";
+      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
+      display.lineNumWidth = display.lineNumInnerWidth + padding;
+      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
+      display.lineGutter.style.width = display.lineNumWidth + "px";
+      updateGutterSpace(cm);
+      return true;
+    }
+    return false;
+  }
+
+  function lineNumberFor(options, i) {
+    return String(options.lineNumberFormatter(i + options.firstLineNumber));
+  }
+
+  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
+  // but using getBoundingClientRect to get a sub-pixel-accurate
+  // result.
+  function compensateForHScroll(display) {
+    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
+  }
+
+  // DISPLAY DRAWING
+
+  function DisplayUpdate(cm, viewport, force) {
+    var display = cm.display;
+
+    this.viewport = viewport;
+    // Store some values that we'll need later (but don't want to force a relayout for)
+    this.visible = visibleLines(display, cm.doc, viewport);
+    this.editorIsHidden = !display.wrapper.offsetWidth;
+    this.wrapperHeight = display.wrapper.clientHeight;
+    this.wrapperWidth = display.wrapper.clientWidth;
+    this.oldDisplayWidth = displayWidth(cm);
+    this.force = force;
+    this.dims = getDimensions(cm);
+    this.events = [];
+  }
+
+  DisplayUpdate.prototype.signal = function(emitter, type) {
+    if (hasHandler(emitter, type))
+      this.events.push(arguments);
+  };
+  DisplayUpdate.prototype.finish = function() {
+    for (var i = 0; i < this.events.length; i++)
+      signal.apply(null, this.events[i]);
+  };
+
+  function maybeClipScrollbars(cm) {
+    var display = cm.display;
+    if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
+      display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
+      display.heightForcer.style.height = scrollGap(cm) + "px";
+      display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
+      display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
+      display.scrollbarsClipped = true;
+    }
+  }
+
+  // Does the actual updating of the line display. Bails out
+  // (returning false) when there is nothing to be done and forced is
+  // false.
+  function updateDisplayIfNeeded(cm, update) {
+    var display = cm.display, doc = cm.doc;
+
+    if (update.editorIsHidden) {
+      resetView(cm);
+      return false;
+    }
+
+    // Bail out if the visible area is already rendered and nothing changed.
+    if (!update.force &&
+        update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
+        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
+        display.renderedView == display.view && countDirtyView(cm) == 0)
+      return false;
+
+    if (maybeUpdateLineNumberWidth(cm)) {
+      resetView(cm);
+      update.dims = getDimensions(cm);
+    }
+
+    // Compute a suitable new viewport (from & to)
+    var end = doc.first + doc.size;
+    var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
+    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
+    if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
+    if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
+    if (sawCollapsedSpans) {
+      from = visualLineNo(cm.doc, from);
+      to = visualLineEndNo(cm.doc, to);
+    }
+
+    var different = from != display.viewFrom || to != display.viewTo ||
+      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
+    adjustView(cm, from, to);
+
+    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
+    // Position the mover div to align with the current scroll position
+    cm.display.mover.style.top = display.viewOffset + "px";
+
+    var toUpdate = countDirtyView(cm);
+    if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
+        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
+      return false;
+
+    // For big changes, we hide the enclosing element during the
+    // update, since that speeds up the operations on most browsers.
+    var focused = activeElt();
+    if (toUpdate > 4) display.lineDiv.style.display = "none";
+    patchDisplay(cm, display.updateLineNumbers, update.dims);
+    if (toUpdate > 4) display.lineDiv.style.display = "";
+    display.renderedView = display.view;
+    // There might have been a widget with a focused element that got
+    // hidden or updated, if so re-focus it.
+    if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
+
+    // Prevent selection and cursors from interfering with the scroll
+    // width and height.
+    removeChildren(display.cursorDiv);
+    removeChildren(display.selectionDiv);
+    display.gutters.style.height = 0;
+
+    if (different) {
+      display.lastWrapHeight = update.wrapperHeight;
+      display.lastWrapWidth = update.wrapperWidth;
+      startWorker(cm, 400);
+    }
+
+    display.updateLineNumbers = null;
+
+    return true;
+  }
+
+  function postUpdateDisplay(cm, update) {
+    var viewport = update.viewport;
+    for (var first = true;; first = false) {
+      if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
+        // Clip forced viewport to actual scrollable area.
+        if (viewport && viewport.top != null)
+          viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
+        // Updated line heights might result in the drawn area not
+        // actually covering the viewport. Keep looping until it does.
+        update.visible = visibleLines(cm.display, cm.doc, viewport);
+        if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
+          break;
+      }
+      if (!updateDisplayIfNeeded(cm, update)) break;
+      updateHeightsInViewport(cm);
+      var barMeasure = measureForScrollbars(cm);
+      updateSelection(cm);
+      setDocumentHeight(cm, barMeasure);
+      updateScrollbars(cm, barMeasure);
+    }
+
+    update.signal(cm, "update", cm);
+    if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
+      update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
+      cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
+    }
+  }
+
+  function updateDisplaySimple(cm, viewport) {
+    var update = new DisplayUpdate(cm, viewport);
+    if (updateDisplayIfNeeded(cm, update)) {
+      updateHeightsInViewport(cm);
+      postUpdateDisplay(cm, update);
+      var barMeasure = measureForScrollbars(cm);
+      updateSelection(cm);
+      setDocumentHeight(cm, barMeasure);
+      updateScrollbars(cm, barMeasure);
+      update.finish();
+    }
+  }
+
+  function setDocumentHeight(cm, measure) {
+    cm.display.sizer.style.minHeight = measure.docHeight + "px";
+    var total = measure.docHeight + cm.display.barHeight;
+    cm.display.heightForcer.style.top = total + "px";
+    cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
+  }
+
+  // Read the actual heights of the rendered lines, and update their
+  // stored heights to match.
+  function updateHeightsInViewport(cm) {
+    var display = cm.display;
+    var prevBottom = display.lineDiv.offsetTop;
+    for (var i = 0; i < display.view.length; i++) {
+      var cur = display.view[i], height;
+      if (cur.hidden) continue;
+      if (ie && ie_version < 8) {
+        var bot = cur.node.offsetTop + cur.node.offsetHeight;
+        height = bot - prevBottom;
+        prevBottom = bot;
+      } else {
+        var box = cur.node.getBoundingClientRect();
+        height = box.bottom - box.top;
+      }
+      var diff = cur.line.height - height;
+      if (height < 2) height = textHeight(display);
+      if (diff > .001 || diff < -.001) {
+        updateLineHeight(cur.line, height);
+        updateWidgetHeight(cur.line);
+        if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
+          updateWidgetHeight(cur.rest[j]);
+      }
+    }
+  }
+
+  // Read and store the height of line widgets associated with the
+  // given line.
+  function updateWidgetHeight(line) {
+    if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
+      line.widgets[i].height = line.widgets[i].node.offsetHeight;
+  }
+
+  // Do a bulk-read of the DOM positions and sizes needed to draw the
+  // view, so that we don't interleave reading and writing to the DOM.
+  function getDimensions(cm) {
+    var d = cm.display, left = {}, width = {};
+    var gutterLeft = d.gutters.clientLeft;
+    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
+      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
+      width[cm.options.gutters[i]] = n.clientWidth;
+    }
+    return {fixedPos: compensateForHScroll(d),
+            gutterTotalWidth: d.gutters.offsetWidth,
+            gutterLeft: left,
+            gutterWidth: width,
+            wrapperWidth: d.wrapper.clientWidth};
+  }
+
+  // Sync the actual display DOM structure with display.view, removing
+  // nodes for lines that are no longer in view, and creating the ones
+  // that are not there yet, and updating the ones that are out of
+  // date.
+  function patchDisplay(cm, updateNumbersFrom, dims) {
+    var display = cm.display, lineNumbers = cm.options.lineNumbers;
+    var container = display.lineDiv, cur = container.firstChild;
+
+    function rm(node) {
+      var next = node.nextSibling;
+      // Works around a throw-scroll bug in OS X Webkit
+      if (webkit && mac && cm.display.currentWheelTarget == node)
+        node.style.display = "none";
+      else
+        node.parentNode.removeChild(node);
+      return next;
+    }
+
+    var view = display.view, lineN = display.viewFrom;
+    // Loop over the elements in the view, syncing cur (the DOM nodes
+    // in display.lineDiv) with the view as we go.
+    for (var i = 0; i < view.length; i++) {
+      var lineView = view[i];
+      if (lineView.hidden) {
+      } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
+        var node = buildLineElement(cm, lineView, lineN, dims);
+        container.insertBefore(node, cur);
+      } else { // Already drawn
+        while (cur != lineView.node) cur = rm(cur);
+        var updateNumber = lineNumbers && updateNumbersFrom != null &&
+          updateNumbersFrom <= lineN && lineView.lineNumber;
+        if (lineView.changes) {
+          if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
+          updateLineForChanges(cm, lineView, lineN, dims);
+        }
+        if (updateNumber) {
+          removeChildren(lineView.lineNumber);
+          lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
+        }
+        cur = lineView.node.nextSibling;
+      }
+      lineN += lineView.size;
+    }
+    while (cur) cur = rm(cur);
+  }
+
+  // When an aspect of a line changes, a string is added to
+  // lineView.changes. This updates the relevant part of the line's
+  // DOM structure.
+  function updateLineForChanges(cm, lineView, lineN, dims) {
+    for (var j = 0; j < lineView.changes.length; j++) {
+      var type = lineView.changes[j];
+      if (type == "text") updateLineText(cm, lineView);
+      else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
+      else if (type == "class") updateLineClasses(lineView);
+      else if (type == "widget") updateLineWidgets(cm, lineView, dims);
+    }
+    lineView.changes = null;
+  }
+
+  // Lines with gutter elements, widgets or a background class need to
+  // be wrapped, and have the extra elements added to the wrapper div
+  function ensureLineWrapped(lineView) {
+    if (lineView.node == lineView.text) {
+      lineView.node = elt("div", null, null, "position: relative");
+      if (lineView.text.parentNode)
+        lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
+      lineView.node.appendChild(lineView.text);
+      if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
+    }
+    return lineView.node;
+  }
+
+  function updateLineBackground(lineView) {
+    var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
+    if (cls) cls += " CodeMirror-linebackground";
+    if (lineView.background) {
+      if (cls) lineView.background.className = cls;
+      else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
+    } else if (cls) {
+      var wrap = ensureLineWrapped(lineView);
+      lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
+    }
+  }
+
+  // Wrapper around buildLineContent which will reuse the structure
+  // in display.externalMeasured when possible.
+  function getLineContent(cm, lineView) {
+    var ext = cm.display.externalMeasured;
+    if (ext && ext.line == lineView.line) {
+      cm.display.externalMeasured = null;
+      lineView.measure = ext.measure;
+      return ext.built;
+    }
+    return buildLineContent(cm, lineView);
+  }
+
+  // Redraw the line's text. Interacts with the background and text
+  // classes because the mode may output tokens that influence these
+  // classes.
+  function updateLineText(cm, lineView) {
+    var cls = lineView.text.className;
+    var built = getLineContent(cm, lineView);
+    if (lineView.text == lineView.node) lineView.node = built.pre;
+    lineView.text.parentNode.replaceChild(built.pre, lineView.text);
+    lineView.text = built.pre;
+    if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
+      lineView.bgClass = built.bgClass;
+      lineView.textClass = built.textClass;
+      updateLineClasses(lineView);
+    } else if (cls) {
+      lineView.text.className = cls;
+    }
+  }
+
+  function updateLineClasses(lineView) {
+    updateLineBackground(lineView);
+    if (lineView.line.wrapClass)
+      ensureLineWrapped(lineView).className = lineView.line.wrapClass;
+    else if (lineView.node != lineView.text)
+      lineView.node.className = "";
+    var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
+    lineView.text.className = textClass || "";
+  }
+
+  function updateLineGutter(cm, lineView, lineN, dims) {
+    if (lineView.gutter) {
+      lineView.node.removeChild(lineView.gutter);
+      lineView.gutter = null;
+    }
+    var markers = lineView.line.gutterMarkers;
+    if (cm.options.lineNumbers || markers) {
+      var wrap = ensureLineWrapped(lineView);
+      var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
+                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
+                                             "px; width: " + dims.gutterTotalWidth + "px");
+      cm.display.input.setUneditable(gutterWrap);
+      wrap.insertBefore(gutterWrap, lineView.text);
+      if (lineView.line.gutterClass)
+        gutterWrap.className += " " + lineView.line.gutterClass;
+      if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
+        lineView.lineNumber = gutterWrap.appendChild(
+          elt("div", lineNumberFor(cm.options, lineN),
+              "CodeMirror-linenumber CodeMirror-gutter-elt",
+              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
+              + cm.display.lineNumInnerWidth + "px"));
+      if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
+        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
+        if (found)
+          gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
+                                     dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
+      }
+    }
+  }
+
+  function updateLineWidgets(cm, lineView, dims) {
+    if (lineView.alignable) lineView.alignable = null;
+    for (var node = lineView.node.firstChild, next; node; node = next) {
+      var next = node.nextSibling;
+      if (node.className == "CodeMirror-linewidget")
+        lineView.node.removeChild(node);
+    }
+    insertLineWidgets(cm, lineView, dims);
+  }
+
+  // Build a line's DOM representation from scratch
+  function buildLineElement(cm, lineView, lineN, dims) {
+    var built = getLineContent(cm, lineView);
+    lineView.text = lineView.node = built.pre;
+    if (built.bgClass) lineView.bgClass = built.bgClass;
+    if (built.textClass) lineView.textClass = built.textClass;
+
+    updateLineClasses(lineView);
+    updateLineGutter(cm, lineView, lineN, dims);
+    insertLineWidgets(cm, lineView, dims);
+    return lineView.node;
+  }
+
+  // A lineView may contain multiple logical lines (when merged by
+  // collapsed spans). The widgets for all of them need to be drawn.
+  function insertLineWidgets(cm, lineView, dims) {
+    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
+    if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+      insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
+  }
+
+  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
+    if (!line.widgets) return;
+    var wrap = ensureLineWrapped(lineView);
+    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
+      var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
+      if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
+      positionLineWidget(widget, node, lineView, dims);
+      cm.display.input.setUneditable(node);
+      if (allowAbove && widget.above)
+        wrap.insertBefore(node, lineView.gutter || lineView.text);
+      else
+        wrap.appendChild(node);
+      signalLater(widget, "redraw");
+    }
+  }
+
+  function positionLineWidget(widget, node, lineView, dims) {
+    if (widget.noHScroll) {
+      (lineView.alignable || (lineView.alignable = [])).push(node);
+      var width = dims.wrapperWidth;
+      node.style.left = dims.fixedPos + "px";
+      if (!widget.coverGutter) {
+        width -= dims.gutterTotalWidth;
+        node.style.paddingLeft = dims.gutterTotalWidth + "px";
+      }
+      node.style.width = width + "px";
+    }
+    if (widget.coverGutter) {
+      node.style.zIndex = 5;
+      node.style.position = "relative";
+      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
+    }
+  }
+
+  // POSITION OBJECT
+
+  // A Pos instance represents a position within the text.
+  var Pos = CodeMirror.Pos = function(line, ch) {
+    if (!(this instanceof Pos)) return new Pos(line, ch);
+    this.line = line; this.ch = ch;
+  };
+
+  // Compare two positions, return 0 if they are the same, a negative
+  // number when a is less, and a positive number otherwise.
+  var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
+
+  function copyPos(x) {return Pos(x.line, x.ch);}
+  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
+  function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
+
+  // INPUT HANDLING
+
+  function ensureFocus(cm) {
+    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
+  }
+
+  function isReadOnly(cm) {
+    return cm.options.readOnly || cm.doc.cantEdit;
+  }
+
+  // This will be set to an array of strings when copying, so that,
+  // when pasting, we know what kind of selections the copied text
+  // was made out of.
+  var lastCopied = null;
+
+  function applyTextInput(cm, inserted, deleted, sel, origin) {
+    var doc = cm.doc;
+    cm.display.shift = false;
+    if (!sel) sel = doc.sel;
+
+    var paste = cm.state.pasteIncoming || origin == "paste";
+    var textLines = splitLines(inserted), multiPaste = null;
+    // When pasing N lines into N selections, insert one line per selection
+    if (paste && sel.ranges.length > 1) {
+      if (lastCopied && lastCopied.join("\n") == inserted)
+        multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
+      else if (textLines.length == sel.ranges.length)
+        multiPaste = map(textLines, function(l) { return [l]; });
+    }
+
+    // Normal behavior is to insert the new text into every selection
+    for (var i = sel.ranges.length - 1; i >= 0; i--) {
+      var range = sel.ranges[i];
+      var from = range.from(), to = range.to();
+      if (range.empty()) {
+        if (deleted && deleted > 0) // Handle deletion
+          from = Pos(from.line, from.ch - deleted);
+        else if (cm.state.overwrite && !paste) // Handle overwrite
+          to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
+      }
+      var updateInput = cm.curOp.updateInput;
+      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
+                         origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
+      makeChange(cm.doc, changeEvent);
+      signalLater(cm, "inputRead", cm, changeEvent);
+    }
+    if (inserted && !paste)
+      triggerElectric(cm, inserted);
+
+    ensureCursorVisible(cm);
+    cm.curOp.updateInput = updateInput;
+    cm.curOp.typing = true;
+    cm.state.pasteIncoming = cm.state.cutIncoming = false;
+  }
+
+  function handlePaste(e, cm) {
+    var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
+    if (pasted) {
+      e.preventDefault();
+      runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
+      return true;
+    }
+  }
+
+  function triggerElectric(cm, inserted) {
+    // When an 'electric' character is inserted, immediately trigger a reindent
+    if (!cm.options.electricChars || !cm.options.smartIndent) return;
+    var sel = cm.doc.sel;
+
+    for (var i = sel.ranges.length - 1; i >= 0; i--) {
+      var range = sel.ranges[i];
+      if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;
+      var mode = cm.getModeAt(range.head);
+      var indented = false;
+      if (mode.electricChars) {
+        for (var j = 0; j < mode.electricChars.length; j++)
+          if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
+            indented = indentLine(cm, range.head.line, "smart");
+            break;
+          }
+      } else if (mode.electricInput) {
+        if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
+          indented = indentLine(cm, range.head.line, "smart");
+      }
+      if (indented) signalLater(cm, "electricInput", cm, range.head.line);
+    }
+  }
+
+  function copyableRanges(cm) {
+    var text = [], ranges = [];
+    for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
+      var line = cm.doc.sel.ranges[i].head.line;
+      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
+      ranges.push(lineRange);
+      text.push(cm.getRange(lineRange.anchor, lineRange.head));
+    }
+    return {text: text, ranges: ranges};
+  }
+
+  function disableBrowserMagic(field) {
+    field.setAttribute("autocorrect", "off");
+    field.setAttribute("autocapitalize", "off");
+    field.setAttribute("spellcheck", "false");
+  }
+
+  // TEXTAREA INPUT STYLE
+
+  function TextareaInput(cm) {
+    this.cm = cm;
+    // See input.poll and input.reset
+    this.prevInput = "";
+
+    // Flag that indicates whether we expect input to appear real soon
+    // now (after some event like 'keypress' or 'input') and are
+    // polling intensively.
+    this.pollingFast = false;
+    // Self-resetting timeout for the poller
+    this.polling = new Delayed();
+    // Tracks when input.reset has punted to just putting a short
+    // string into the textarea instead of the full selection.
+    this.inaccurateSelection = false;
+    // Used to work around IE issue with selection being forgotten when focus moves away from textarea
+    this.hasSelection = false;
+    this.composing = null;
+  };
+
+  function hiddenTextarea() {
+    var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
+    var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
+    // The textarea is kept positioned near the cursor to prevent the
+    // fact that it'll be scrolled into view on input from scrolling
+    // our fake cursor out of view. On webkit, when wrap=off, paste is
+    // very slow. So make the area wide instead.
+    if (webkit) te.style.width = "1000px";
+    else te.setAttribute("wrap", "off");
+    // If border: 0; -- iOS fails to open keyboard (issue #1287)
+    if (ios) te.style.border = "1px solid black";
+    disableBrowserMagic(te);
+    return div;
+  }
+
+  TextareaInput.prototype = copyObj({
+    init: function(display) {
+      var input = this, cm = this.cm;
+
+      // Wraps and hides input textarea
+      var div = this.wrapper = hiddenTextarea();
+      // The semihidden textarea that is focused when the editor is
+      // focused, and receives input.
+      var te = this.textarea = div.firstChild;
+      display.wrapper.insertBefore(div, display.wrapper.firstChild);
+
+      // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
+      if (ios) te.style.width = "0px";
+
+      on(te, "input", function() {
+        if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
+        input.poll();
+      });
+
+      on(te, "paste", function(e) {
+        if (handlePaste(e, cm)) return true;
+
+        cm.state.pasteIncoming = true;
+        input.fastPoll();
+      });
+
+      function prepareCopyCut(e) {
+        if (cm.somethingSelected()) {
+          lastCopied = cm.getSelections();
+          if (input.inaccurateSelection) {
+            input.prevInput = "";
+            input.inaccurateSelection = false;
+            te.value = lastCopied.join("\n");
+            selectInput(te);
+          }
+        } else if (!cm.options.lineWiseCopyCut) {
+          return;
+        } else {
+          var ranges = copyableRanges(cm);
+          lastCopied = ranges.text;
+          if (e.type == "cut") {
+            cm.setSelections(ranges.ranges, null, sel_dontScroll);
+          } else {
+            input.prevInput = "";
+            te.value = ranges.text.join("\n");
+            selectInput(te);
+          }
+        }
+        if (e.type == "cut") cm.state.cutIncoming = true;
+      }
+      on(te, "cut", prepareCopyCut);
+      on(te, "copy", prepareCopyCut);
+
+      on(display.scroller, "paste", function(e) {
+        if (eventInWidget(display, e)) return;
+        cm.state.pasteIncoming = true;
+        input.focus();
+      });
+
+      // Prevent normal selection in the editor (we handle our own)
+      on(display.lineSpace, "selectstart", function(e) {
+        if (!eventInWidget(display, e)) e_preventDefault(e);
+      });
+
+      on(te, "compositionstart", function() {
+        var start = cm.getCursor("from");
+        input.composing = {
+          start: start,
+          range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
+        };
+      });
+      on(te, "compositionend", function() {
+        if (input.composing) {
+          input.poll();
+          input.composing.range.clear();
+          input.composing = null;
+        }
+      });
+    },
+
+    prepareSelection: function() {
+      // Redraw the selection and/or cursor
+      var cm = this.cm, display = cm.display, doc = cm.doc;
+      var result = prepareSelection(cm);
+
+      // Move the hidden textarea near the cursor to prevent scrolling artifacts
+      if (cm.options.moveInputWithCursor) {
+        var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
+        var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
+        result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
+                                            headPos.top + lineOff.top - wrapOff.top));
+        result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
+                                             headPos.left + lineOff.left - wrapOff.left));
+      }
+
+      return result;
+    },
+
+    showSelection: function(drawn) {
+      var cm = this.cm, display = cm.display;
+      removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
+      removeChildrenAndAdd(display.selectionDiv, drawn.selection);
+      if (drawn.teTop != null) {
+        this.wrapper.style.top = drawn.teTop + "px";
+        this.wrapper.style.left = drawn.teLeft + "px";
+      }
+    },
+
+    // Reset the input to correspond to the selection (or to be empty,
+    // when not typing and nothing is selected)
+    reset: function(typing) {
+      if (this.contextMenuPending) return;
+      var minimal, selected, cm = this.cm, doc = cm.doc;
+      if (cm.somethingSelected()) {
+        this.prevInput = "";
+        var range = doc.sel.primary();
+        minimal = hasCopyEvent &&
+          (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
+        var content = minimal ? "-" : selected || cm.getSelection();
+        this.textarea.value = content;
+        if (cm.state.focused) selectInput(this.textarea);
+        if (ie && ie_version >= 9) this.hasSelection = content;
+      } else if (!typing) {
+        this.prevInput = this.textarea.value = "";
+        if (ie && ie_version >= 9) this.hasSelection = null;
+      }
+      this.inaccurateSelection = minimal;
+    },
+
+    getField: function() { return this.textarea; },
+
+    supportsTouch: function() { return false; },
+
+    focus: function() {
+      if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
+        try { this.textarea.focus(); }
+        catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
+      }
+    },
+
+    blur: function() { this.textarea.blur(); },
+
+    resetPosition: function() {
+      this.wrapper.style.top = this.wrapper.style.left = 0;
+    },
+
+    receivedFocus: function() { this.slowPoll(); },
+
+    // Poll for input changes, using the normal rate of polling. This
+    // runs as long as the editor is focused.
+    slowPoll: function() {
+      var input = this;
+      if (input.pollingFast) return;
+      input.polling.set(this.cm.options.pollInterval, function() {
+        input.poll();
+        if (input.cm.state.focused) input.slowPoll();
+      });
+    },
+
+    // When an event has just come in that is likely to add or change
+    // something in the input textarea, we poll faster, to ensure that
+    // the change appears on the screen quickly.
+    fastPoll: function() {
+      var missed = false, input = this;
+      input.pollingFast = true;
+      function p() {
+        var changed = input.poll();
+        if (!changed && !missed) {missed = true; input.polling.set(60, p);}
+        else {input.pollingFast = false; input.slowPoll();}
+      }
+      input.polling.set(20, p);
+    },
+
+    // Read input from the textarea, and update the document to match.
+    // When something is selected, it is present in the textarea, and
+    // selected (unless it is huge, in which case a placeholder is
+    // used). When nothing is selected, the cursor sits after previously
+    // seen text (can be empty), which is stored in prevInput (we must
+    // not reset the textarea when typing, because that breaks IME).
+    poll: function() {
+      var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
+      // Since this is called a *lot*, try to bail out as cheaply as
+      // possible when it is clear that nothing happened. hasSelection
+      // will be the case when there is a lot of text in the textarea,
+      // in which case reading its value would be expensive.
+      if (this.contextMenuPending || !cm.state.focused ||
+          (hasSelection(input) && !prevInput) ||
+          isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
+        return false;
+
+      var text = input.value;
+      // If nothing changed, bail.
+      if (text == prevInput && !cm.somethingSelected()) return false;
+      // Work around nonsensical selection resetting in IE9/10, and
+      // inexplicable appearance of private area unicode characters on
+      // some key combos in Mac (#2689).
+      if (ie && ie_version >= 9 && this.hasSelection === text ||
+          mac && /[\uf700-\uf7ff]/.test(text)) {
+        cm.display.input.reset();
+        return false;
+      }
+
+      if (cm.doc.sel == cm.display.selForContextMenu) {
+        var first = text.charCodeAt(0);
+        if (first == 0x200b && !prevInput) prevInput = "\u200b";
+        if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
+      }
+      // Find the part of the input that is actually new
+      var same = 0, l = Math.min(prevInput.length, text.length);
+      while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
+
+      var self = this;
+      runInOp(cm, function() {
+        applyTextInput(cm, text.slice(same), prevInput.length - same,
+                       null, self.composing ? "*compose" : null);
+
+        // Don't leave long text in the textarea, since it makes further polling slow
+        if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
+        else self.prevInput = text;
+
+        if (self.composing) {
+          self.composing.range.clear();
+          self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
+                                             {className: "CodeMirror-composing"});
+        }
+      });
+      return true;
+    },
+
+    ensurePolled: function() {
+      if (this.pollingFast && this.poll()) this.pollingFast = false;
+    },
+
+    onKeyPress: function() {
+      if (ie && ie_version >= 9) this.hasSelection = null;
+      this.fastPoll();
+    },
+
+    onContextMenu: function(e) {
+      var input = this, cm = input.cm, display = cm.display, te = input.textarea;
+      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
+      if (!pos || presto) return; // Opera is difficult.
+
+      // Reset the current text selection only if the click is done outside of the selection
+      // and 'resetSelectionOnContextMenu' option is true.
+      var reset = cm.options.resetSelectionOnContextMenu;
+      if (reset && cm.doc.sel.contains(pos) == -1)
+        operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
+
+      var oldCSS = te.style.cssText;
+      input.wrapper.style.position = "absolute";
+      te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
+        "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
+        (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
+        "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
+      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
+      display.input.focus();
+      if (webkit) window.scrollTo(null, oldScrollY);
+      display.input.reset();
+      // Adds "Select all" to context menu in FF
+      if (!cm.somethingSelected()) te.value = input.prevInput = " ";
+      input.contextMenuPending = true;
+      display.selForContextMenu = cm.doc.sel;
+      clearTimeout(display.detectingSelectAll);
+
+      // Select-all will be greyed out if there's nothing to select, so
+      // this adds a zero-width space so that we can later check whether
+      // it got selected.
+      function prepareSelectAllHack() {
+        if (te.selectionStart != null) {
+          var selected = cm.somethingSelected();
+          var extval = "\u200b" + (selected ? te.value : "");
+          te.value = "\u21da"; // Used to catch context-menu undo
+          te.value = extval;
+          input.prevInput = selected ? "" : "\u200b";
+          te.selectionStart = 1; te.selectionEnd = extval.length;
+          // Re-set this, in case some other handler touched the
+          // selection in the meantime.
+          display.selForContextMenu = cm.doc.sel;
+        }
+      }
+      function rehide() {
+        input.contextMenuPending = false;
+        input.wrapper.style.position = "relative";
+        te.style.cssText = oldCSS;
+        if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
+
+        // Try to detect the user choosing select-all
+        if (te.selectionStart != null) {
+          if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
+          var i = 0, poll = function() {
+            if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
+                te.selectionEnd > 0 && input.prevInput == "\u200b")
+              operation(cm, commands.selectAll)(cm);
+            else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
+            else display.input.reset();
+          };
+          display.detectingSelectAll = setTimeout(poll, 200);
+        }
+      }
+
+      if (ie && ie_version >= 9) prepareSelectAllHack();
+      if (captureRightClick) {
+        e_stop(e);
+        var mouseup = function() {
+          off(window, "mouseup", mouseup);
+          setTimeout(rehide, 20);
+        };
+        on(window, "mouseup", mouseup);
+      } else {
+        setTimeout(rehide, 50);
+      }
+    },
+
+    setUneditable: nothing,
+
+    needsContentAttribute: false
+  }, TextareaInput.prototype);
+
+  // CONTENTEDITABLE INPUT STYLE
+
+  function ContentEditableInput(cm) {
+    this.cm = cm;
+    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
+    this.polling = new Delayed();
+    this.gracePeriod = false;
+  }
+
+  ContentEditableInput.prototype = copyObj({
+    init: function(display) {
+      var input = this, cm = input.cm;
+      var div = input.div = display.lineDiv;
+      div.contentEditable = "true";
+      disableBrowserMagic(div);
+
+      on(div, "paste", function(e) { handlePaste(e, cm); })
+
+      on(div, "compositionstart", function(e) {
+        var data = e.data;
+        input.composing = {sel: cm.doc.sel, data: data, startData: data};
+        if (!data) return;
+        var prim = cm.doc.sel.primary();
+        var line = cm.getLine(prim.head.line);
+        var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
+        if (found > -1 && found <= prim.head.ch)
+          input.composing.sel = simpleSelection(Pos(prim.head.line, found),
+                                                Pos(prim.head.line, found + data.length));
+      });
+      on(div, "compositionupdate", function(e) {
+        input.composing.data = e.data;
+      });
+      on(div, "compositionend", function(e) {
+        var ours = input.composing;
+        if (!ours) return;
+        if (e.data != ours.startData && !/\u200b/.test(e.data))
+          ours.data = e.data;
+        // Need a small delay to prevent other code (input event,
+        // selection polling) from doing damage when fired right after
+        // compositionend.
+        setTimeout(function() {
+          if (!ours.handled)
+            input.applyComposition(ours);
+          if (input.composing == ours)
+            input.composing = null;
+        }, 50);
+      });
+
+      on(div, "touchstart", function() {
+        input.forceCompositionEnd();
+      });
+
+      on(div, "input", function() {
+        if (input.composing) return;
+        if (!input.pollContent())
+          runInOp(input.cm, function() {regChange(cm);});
+      });
+
+      function onCopyCut(e) {
+        if (cm.somethingSelected()) {
+          lastCopied = cm.getSelections();
+          if (e.type == "cut") cm.replaceSelection("", null, "cut");
+        } else if (!cm.options.lineWiseCopyCut) {
+          return;
+        } else {
+          var ranges = copyableRanges(cm);
+          lastCopied = ranges.text;
+          if (e.type == "cut") {
+            cm.operation(function() {
+              cm.setSelections(ranges.ranges, 0, sel_dontScroll);
+              cm.replaceSelection("", null, "cut");
+            });
+          }
+        }
+        // iOS exposes the clipboard API, but seems to discard content inserted into it
+        if (e.clipboardData && !ios) {
+          e.preventDefault();
+          e.clipboardData.clearData();
+          e.clipboardData.setData("text/plain", lastCopied.join("\n"));
+        } else {
+          // Old-fashioned briefly-focus-a-textarea hack
+          var kludge = hiddenTextarea(), te = kludge.firstChild;
+          cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
+          te.value = lastCopied.join("\n");
+          var hadFocus = document.activeElement;
+          selectInput(te);
+          setTimeout(function() {
+            cm.display.lineSpace.removeChild(kludge);
+            hadFocus.focus();
+          }, 50);
+        }
+      }
+      on(div, "copy", onCopyCut);
+      on(div, "cut", onCopyCut);
+    },
+
+    prepareSelection: function() {
+      var result = prepareSelection(this.cm, false);
+      result.focus = this.cm.state.focused;
+      return result;
+    },
+
+    showSelection: function(info) {
+      if (!info || !this.cm.display.view.length) return;
+      if (info.focus) this.showPrimarySelection();
+      this.showMultipleSelections(info);
+    },
+
+    showPrimarySelection: function() {
+      var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
+      var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
+      var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
+      if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
+          cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
+          cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
+        return;
+
+      var start = posToDOM(this.cm, prim.from());
+      var end = posToDOM(this.cm, prim.to());
+      if (!start && !end) return;
+
+      var view = this.cm.display.view;
+      var old = sel.rangeCount && sel.getRangeAt(0);
+      if (!start) {
+        start = {node: view[0].measure.map[2], offset: 0};
+      } else if (!end) { // FIXME dangerously hacky
+        var measure = view[view.length - 1].measure;
+        var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
+        end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
+      }
+
+      try { var rng = range(start.node, start.offset, end.offset, end.node); }
+      catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
+      if (rng) {
+        sel.removeAllRanges();
+        sel.addRange(rng);
+        if (old && sel.anchorNode == null) sel.addRange(old);
+        else if (gecko) this.startGracePeriod();
+      }
+      this.rememberSelection();
+    },
+
+    startGracePeriod: function() {
+      var input = this;
+      clearTimeout(this.gracePeriod);
+      this.gracePeriod = setTimeout(function() {
+        input.gracePeriod = false;
+        if (input.selectionChanged())
+          input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
+      }, 20);
+    },
+
+    showMultipleSelections: function(info) {
+      removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
+      removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
+    },
+
+    rememberSelection: function() {
+      var sel = window.getSelection();
+      this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
+      this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
+    },
+
+    selectionInEditor: function() {
+      var sel = window.getSelection();
+      if (!sel.rangeCount) return false;
+      var node = sel.getRangeAt(0).commonAncestorContainer;
+      return contains(this.div, node);
+    },
+
+    focus: function() {
+      if (this.cm.options.readOnly != "nocursor") this.div.focus();
+    },
+    blur: function() { this.div.blur(); },
+    getField: function() { return this.div; },
+
+    supportsTouch: function() { return true; },
+
+    receivedFocus: function() {
+      var input = this;
+      if (this.selectionInEditor())
+        this.pollSelection();
+      else
+        runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
+
+      function poll() {
+        if (input.cm.state.focused) {
+          input.pollSelection();
+          input.polling.set(input.cm.options.pollInterval, poll);
+        }
+      }
+      this.polling.set(this.cm.options.pollInterval, poll);
+    },
+
+    selectionChanged: function() {
+      var sel = window.getSelection();
+      return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
+        sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
+    },
+
+    pollSelection: function() {
+      if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
+        var sel = window.getSelection(), cm = this.cm;
+        this.rememberSelection();
+        var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
+        var head = domToPos(cm, sel.focusNode, sel.focusOffset);
+        if (anchor && head) runInOp(cm, function() {
+          setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
+          if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
+        });
+      }
+    },
+
+    pollContent: function() {
+      var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
+      var from = sel.from(), to = sel.to();
+      if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
+
+      var fromIndex;
+      if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
+        var fromLine = lineNo(display.view[0].line);
+        var fromNode = display.view[0].node;
+      } else {
+        var fromLine = lineNo(display.view[fromIndex].line);
+        var fromNode = display.view[fromIndex - 1].node.nextSibling;
+      }
+      var toIndex = findViewIndex(cm, to.line);
+      if (toIndex == display.view.length - 1) {
+        var toLine = display.viewTo - 1;
+        var toNode = display.lineDiv.lastChild;
+      } else {
+        var toLine = lineNo(display.view[toIndex + 1].line) - 1;
+        var toNode = display.view[toIndex + 1].node.previousSibling;
+      }
+
+      var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
+      var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
+      while (newText.length > 1 && oldText.length > 1) {
+        if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
+        else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
+        else break;
+      }
+
+      var cutFront = 0, cutEnd = 0;
+      var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
+      while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
+        ++cutFront;
+      var newBot = lst(newText), oldBot = lst(oldText);
+      var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
+                               oldBot.length - (oldText.length == 1 ? cutFront : 0));
+      while (cutEnd < maxCutEnd &&
+             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
+        ++cutEnd;
+
+      newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
+      newText[0] = newText[0].slice(cutFront);
+
+      var chFrom = Pos(fromLine, cutFront);
+      var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
+      if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
+        replaceRange(cm.doc, newText, chFrom, chTo, "+input");
+        return true;
+      }
+    },
+
+    ensurePolled: function() {
+      this.forceCompositionEnd();
+    },
+    reset: function() {
+      this.forceCompositionEnd();
+    },
+    forceCompositionEnd: function() {
+      if (!this.composing || this.composing.handled) return;
+      this.applyComposition(this.composing);
+      this.composing.handled = true;
+      this.div.blur();
+      this.div.focus();
+    },
+    applyComposition: function(composing) {
+      if (composing.data && composing.data != composing.startData)
+        operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
+    },
+
+    setUneditable: function(node) {
+      node.setAttribute("contenteditable", "false");
+    },
+
+    onKeyPress: function(e) {
+      e.preventDefault();
+      operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
+    },
+
+    onContextMenu: nothing,
+    resetPosition: nothing,
+
+    needsContentAttribute: true
+  }, ContentEditableInput.prototype);
+
+  function posToDOM(cm, pos) {
+    var view = findViewForLine(cm, pos.line);
+    if (!view || view.hidden) return null;
+    var line = getLine(cm.doc, pos.line);
+    var info = mapFromLineView(view, line, pos.line);
+
+    var order = getOrder(line), side = "left";
+    if (order) {
+      var partPos = getBidiPartAt(order, pos.ch);
+      side = partPos % 2 ? "right" : "left";
+    }
+    var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
+    result.offset = result.collapse == "right" ? result.end : result.start;
+    return result;
+  }
+
+  function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
+
+  function domToPos(cm, node, offset) {
+    var lineNode;
+    if (node == cm.display.lineDiv) {
+      lineNode = cm.display.lineDiv.childNodes[offset];
+      if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
+      node = null; offset = 0;
+    } else {
+      for (lineNode = node;; lineNode = lineNode.parentNode) {
+        if (!lineNode || lineNode == cm.display.lineDiv) return null;
+        if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
+      }
+    }
+    for (var i = 0; i < cm.display.view.length; i++) {
+      var lineView = cm.display.view[i];
+      if (lineView.node == lineNode)
+        return locateNodeInLineView(lineView, node, offset);
+    }
+  }
+
+  function locateNodeInLineView(lineView, node, offset) {
+    var wrapper = lineView.text.firstChild, bad = false;
+    if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
+    if (node == wrapper) {
+      bad = true;
+      node = wrapper.childNodes[offset];
+      offset = 0;
+      if (!node) {
+        var line = lineView.rest ? lst(lineView.rest) : lineView.line;
+        return badPos(Pos(lineNo(line), line.text.length), bad);
+      }
+    }
+
+    var textNode = node.nodeType == 3 ? node : null, topNode = node;
+    if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
+      textNode = node.firstChild;
+      if (offset) offset = textNode.nodeValue.length;
+    }
+    while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
+    var measure = lineView.measure, maps = measure.maps;
+
+    function find(textNode, topNode, offset) {
+      for (var i = -1; i < (maps ? maps.length : 0); i++) {
+        var map = i < 0 ? measure.map : maps[i];
+        for (var j = 0; j < map.length; j += 3) {
+          var curNode = map[j + 2];
+          if (curNode == textNode || curNode == topNode) {
+            var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
+            var ch = map[j] + offset;
+            if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
+            return Pos(line, ch);
+          }
+        }
+      }
+    }
+    var found = find(textNode, topNode, offset);
+    if (found) return badPos(found, bad);
+
+    // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
+    for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
+      found = find(after, after.firstChild, 0);
+      if (found)
+        return badPos(Pos(found.line, found.ch - dist), bad);
+      else
+        dist += after.textContent.length;
+    }
+    for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
+      found = find(before, before.firstChild, -1);
+      if (found)
+        return badPos(Pos(found.line, found.ch + dist), bad);
+      else
+        dist += after.textContent.length;
+    }
+  }
+
+  function domTextBetween(cm, from, to, fromLine, toLine) {
+    var text = "", closing = false;
+    function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
+    function walk(node) {
+      if (node.nodeType == 1) {
+        var cmText = node.getAttribute("cm-text");
+        if (cmText != null) {
+          if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
+          text += cmText;
+          return;
+        }
+        var markerID = node.getAttribute("cm-marker"), range;
+        if (markerID) {
+          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
+          if (found.length && (range = found[0].find()))
+            text += getBetween(cm.doc, range.from, range.to).join("\n");
+          return;
+        }
+        if (node.getAttribute("contenteditable") == "false") return;
+        for (var i = 0; i < node.childNodes.length; i++)
+          walk(node.childNodes[i]);
+        if (/^(pre|div|p)$/i.test(node.nodeName))
+          closing = true;
+      } else if (node.nodeType == 3) {
+        var val = node.nodeValue;
+        if (!val) return;
+        if (closing) {
+          text += "\n";
+          closing = false;
+        }
+        text += val;
+      }
+    }
+    for (;;) {
+      walk(from);
+      if (from == to) break;
+      from = from.nextSibling;
+    }
+    return text;
+  }
+
+  CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
+
+  // SELECTION / CURSOR
+
+  // Selection objects are immutable. A new one is created every time
+  // the selection changes. A selection is one or more non-overlapping
+  // (and non-touching) ranges, sorted, and an integer that indicates
+  // which one is the primary selection (the one that's scrolled into
+  // view, that getCursor returns, etc).
+  function Selection(ranges, primIndex) {
+    this.ranges = ranges;
+    this.primIndex = primIndex;
+  }
+
+  Selection.prototype = {
+    primary: function() { return this.ranges[this.primIndex]; },
+    equals: function(other) {
+      if (other == this) return true;
+      if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
+      for (var i = 0; i < this.ranges.length; i++) {
+        var here = this.ranges[i], there = other.ranges[i];
+        if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
+      }
+      return true;
+    },
+    deepCopy: function() {
+      for (var out = [], i = 0; i < this.ranges.length; i++)
+        out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
+      return new Selection(out, this.primIndex);
+    },
+    somethingSelected: function() {
+      for (var i = 0; i < this.ranges.length; i++)
+        if (!this.ranges[i].empty()) return true;
+      return false;
+    },
+    contains: function(pos, end) {
+      if (!end) end = pos;
+      for (var i = 0; i < this.ranges.length; i++) {
+        var range = this.ranges[i];
+        if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
+          return i;
+      }
+      return -1;
+    }
+  };
+
+  function Range(anchor, head) {
+    this.anchor = anchor; this.head = head;
+  }
+
+  Range.prototype = {
+    from: function() { return minPos(this.anchor, this.head); },
+    to: function() { return maxPos(this.anchor, this.head); },
+    empty: function() {
+      return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
+    }
+  };
+
+  // Take an unsorted, potentially overlapping set of ranges, and
+  // build a selection out of it. 'Consumes' ranges array (modifying
+  // it).
+  function normalizeSelection(ranges, primIndex) {
+    var prim = ranges[primIndex];
+    ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
+    primIndex = indexOf(ranges, prim);
+    for (var i = 1; i < ranges.length; i++) {
+      var cur = ranges[i], prev = ranges[i - 1];
+      if (cmp(prev.to(), cur.from()) >= 0) {
+        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
+        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
+        if (i <= primIndex) --primIndex;
+        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
+      }
+    }
+    return new Selection(ranges, primIndex);
+  }
+
+  function simpleSelection(anchor, head) {
+    return new Selection([new Range(anchor, head || anchor)], 0);
+  }
+
+  // Most of the external API clips given positions to make sure they
+  // actually exist within the document.
+  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
+  function clipPos(doc, pos) {
+    if (pos.line < doc.first) return Pos(doc.first, 0);
+    var last = doc.first + doc.size - 1;
+    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
+    return clipToLen(pos, getLine(doc, pos.line).text.length);
+  }
+  function clipToLen(pos, linelen) {
+    var ch = pos.ch;
+    if (ch == null || ch > linelen) return Pos(pos.line, linelen);
+    else if (ch < 0) return Pos(pos.line, 0);
+    else return pos;
+  }
+  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
+  function clipPosArray(doc, array) {
+    for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
+    return out;
+  }
+
+  // SELECTION UPDATES
+
+  // The 'scroll' parameter given to many of these indicated whether
+  // the new cursor position should be scrolled into view after
+  // modifying the selection.
+
+  // If shift is held or the extend flag is set, extends a range to
+  // include a given position (and optionally a second position).
+  // Otherwise, simply returns the range between the given positions.
+  // Used for cursor motion and such.
+  function extendRange(doc, range, head, other) {
+    if (doc.cm && doc.cm.display.shift || doc.extend) {
+      var anchor = range.anchor;
+      if (other) {
+        var posBefore = cmp(head, anchor) < 0;
+        if (posBefore != (cmp(other, anchor) < 0)) {
+          anchor = head;
+          head = other;
+        } else if (posBefore != (cmp(head, other) < 0)) {
+          head = other;
+        }
+      }
+      return new Range(anchor, head);
+    } else {
+      return new Range(other || head, head);
+    }
+  }
+
+  // Extend the primary selection range, discard the rest.
+  function extendSelection(doc, head, other, options) {
+    setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
+  }
+
+  // Extend all selections (pos is an array of selections with length
+  // equal the number of selections)
+  function extendSelections(doc, heads, options) {
+    for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
+      out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
+    var newSel = normalizeSelection(out, doc.sel.primIndex);
+    setSelection(doc, newSel, options);
+  }
+
+  // Updates a single range in the selection.
+  function replaceOneSelection(doc, i, range, options) {
+    var ranges = doc.sel.ranges.slice(0);
+    ranges[i] = range;
+    setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
+  }
+
+  // Reset the selection to a single range.
+  function setSimpleSelection(doc, anchor, head, options) {
+    setSelection(doc, simpleSelection(anchor, head), options);
+  }
+
+  // Give beforeSelectionChange handlers a change to influence a
+  // selection update.
+  function filterSelectionChange(doc, sel) {
+    var obj = {
+      ranges: sel.ranges,
+      update: function(ranges) {
+        this.ranges = [];
+        for (var i = 0; i < ranges.length; i++)
+          this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
+                                     clipPos(doc, ranges[i].head));
+      }
+    };
+    signal(doc, "beforeSelectionChange", doc, obj);
+    if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
+    if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
+    else return sel;
+  }
+
+  function setSelectionReplaceHistory(doc, sel, options) {
+    var done = doc.history.done, last = lst(done);
+    if (last && last.ranges) {
+      done[done.length - 1] = sel;
+      setSelectionNoUndo(doc, sel, options);
+    } else {
+      setSelection(doc, sel, options);
+    }
+  }
+
+  // Set a new selection.
+  function setSelection(doc, sel, options) {
+    setSelectionNoUndo(doc, sel, options);
+    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
+  }
+
+  function setSelectionNoUndo(doc, sel, options) {
+    if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
+      sel = filterSelectionChange(doc, sel);
+
+    var bias = options && options.bias ||
+      (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
+    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
+
+    if (!(options && options.scroll === false) && doc.cm)
+      ensureCursorVisible(doc.cm);
+  }
+
+  function setSelectionInner(doc, sel) {
+    if (sel.equals(doc.sel)) return;
+
+    doc.sel = sel;
+
+    if (doc.cm) {
+      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
+      signalCursorActivity(doc.cm);
+    }
+    signalLater(doc, "cursorActivity", doc);
+  }
+
+  // Verify that the selection does not partially select any atomic
+  // marked ranges.
+  function reCheckSelection(doc) {
+    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
+  }
+
+  // Return a selection that does not partially select any atomic
+  // ranges.
+  function skipAtomicInSelection(doc, sel, bias, mayClear) {
+    var out;
+    for (var i = 0; i < sel.ranges.length; i++) {
+      var range = sel.ranges[i];
+      var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
+      var newHead = skipAtomic(doc, range.head, bias, mayClear);
+      if (out || newAnchor != range.anchor || newHead != range.head) {
+        if (!out) out = sel.ranges.slice(0, i);
+        out[i] = new Range(newAnchor, newHead);
+      }
+    }
+    return out ? normalizeSelection(out, sel.primIndex) : sel;
+  }
+
+  // Ensure a given position is not inside an atomic range.
+  function skipAtomic(doc, pos, bias, mayClear) {
+    var flipped = false, curPos = pos;
+    var dir = bias || 1;
+    doc.cantEdit = false;
+    search: for (;;) {
+      var line = getLine(doc, curPos.line);
+      if (line.markedSpans) {
+        for (var i = 0; i < line.markedSpans.length; ++i) {
+          var sp = line.markedSpans[i], m = sp.marker;
+          if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
+              (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
+            if (mayClear) {
+              signal(m, "beforeCursorEnter");
+              if (m.explicitlyCleared) {
+                if (!line.markedSpans) break;
+                else {--i; continue;}
+              }
+            }
+            if (!m.atomic) continue;
+            var newPos = m.find(dir < 0 ? -1 : 1);
+            if (cmp(newPos, curPos) == 0) {
+              newPos.ch += dir;
+              if (newPos.ch < 0) {
+                if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
+                else newPos = null;
+              } else if (newPos.ch > line.text.length) {
+                if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
+                else newPos = null;
+              }
+              if (!newPos) {
+                if (flipped) {
+                  // Driven in a corner -- no valid cursor position found at all
+                  // -- try again *with* clearing, if we didn't already
+                  if (!mayClear) return skipAtomic(doc, pos, bias, true);
+                  // Otherwise, turn off editing until further notice, and return the start of the doc
+                  doc.cantEdit = true;
+                  return Pos(doc.first, 0);
+                }
+                flipped = true; newPos = pos; dir = -dir;
+              }
+            }
+            curPos = newPos;
+            continue search;
+          }
+        }
+      }
+      return curPos;
+    }
+  }
+
+  // SELECTION DRAWING
+
+  function updateSelection(cm) {
+    cm.display.input.showSelection(cm.display.input.prepareSelection());
+  }
+
+  function prepareSelection(cm, primary) {
+    var doc = cm.doc, result = {};
+    var curFragment = result.cursors = document.createDocumentFragment();
+    var selFragment = result.selection = document.createDocumentFragment();
+
+    for (var i = 0; i < doc.sel.ranges.length; i++) {
+      if (primary === false && i == doc.sel.primIndex) continue;
+      var range = doc.sel.ranges[i];
+      var collapsed = range.empty();
+      if (collapsed || cm.options.showCursorWhenSelecting)
+        drawSelectionCursor(cm, range, curFragment);
+      if (!collapsed)
+        drawSelectionRange(cm, range, selFragment);
+    }
+    return result;
+  }
+
+  // Draws a cursor for the given range
+  function drawSelectionCursor(cm, range, output) {
+    var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
+
+    var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
+    cursor.style.left = pos.left + "px";
+    cursor.style.top = pos.top + "px";
+    cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
+
+    if (pos.other) {
+      // Secondary cursor, shown when on a 'jump' in bi-directional text
+      var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
+      otherCursor.style.display = "";
+      otherCursor.style.left = pos.other.left + "px";
+      otherCursor.style.top = pos.other.top + "px";
+      otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
+    }
+  }
+
+  // Draws the given range as a highlighted selection
+  function drawSelectionRange(cm, range, output) {
+    var display = cm.display, doc = cm.doc;
+    var fragment = document.createDocumentFragment();
+    var padding = paddingH(cm.display), leftSide = padding.left;
+    var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
+
+    function add(left, top, width, bottom) {
+      if (top < 0) top = 0;
+      top = Math.round(top);
+      bottom = Math.round(bottom);
+      fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
+                               "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
+                               "px; height: " + (bottom - top) + "px"));
+    }
+
+    function drawForLine(line, fromArg, toArg) {
+      var lineObj = getLine(doc, line);
+      var lineLen = lineObj.text.length;
+      var start, end;
+      function coords(ch, bias) {
+        return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
+      }
+
+      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
+        var leftPos = coords(from, "left"), rightPos, left, right;
+        if (from == to) {
+          rightPos = leftPos;
+          left = right = leftPos.left;
+        } else {
+          rightPos = coords(to - 1, "right");
+          if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
+          left = leftPos.left;
+          right = rightPos.right;
+        }
+        if (fromArg == null && from == 0) left = leftSide;
+        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
+          add(left, leftPos.top, null, leftPos.bottom);
+          left = leftSide;
+          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
+        }
+        if (toArg == null && to == lineLen) right = rightSide;
+        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
+          start = leftPos;
+        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
+          end = rightPos;
+        if (left < leftSide + 1) left = leftSide;
+        add(left, rightPos.top, right - left, rightPos.bottom);
+      });
+      return {start: start, end: end};
+    }
+
+    var sFrom = range.from(), sTo = range.to();
+    if (sFrom.line == sTo.line) {
+      drawForLine(sFrom.line, sFrom.ch, sTo.ch);
+    } else {
+      var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
+      var singleVLine = visualLine(fromLine) == visualLine(toLine);
+      var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
+      var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
+      if (singleVLine) {
+        if (leftEnd.top < rightStart.top - 2) {
+          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
+          add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
+        } else {
+          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
+        }
+      }
+      if (leftEnd.bottom < rightStart.top)
+        add(leftSide, leftEnd.bottom, null, rightStart.top);
+    }
+
+    output.appendChild(fragment);
+  }
+
+  // Cursor-blinking
+  function restartBlink(cm) {
+    if (!cm.state.focused) return;
+    var display = cm.display;
+    clearInterval(display.blinker);
+    var on = true;
+    display.cursorDiv.style.visibility = "";
+    if (cm.options.cursorBlinkRate > 0)
+      display.blinker = setInterval(function() {
+        display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
+      }, cm.options.cursorBlinkRate);
+    else if (cm.options.cursorBlinkRate < 0)
+      display.cursorDiv.style.visibility = "hidden";
+  }
+
+  // HIGHLIGHT WORKER
+
+  function startWorker(cm, time) {
+    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
+      cm.state.highlight.set(time, bind(highlightWorker, cm));
+  }
+
+  function highlightWorker(cm) {
+    var doc = cm.doc;
+    if (doc.frontier < doc.first) doc.frontier = doc.first;
+    if (doc.frontier >= cm.display.viewTo) return;
+    var end = +new Date + cm.options.workTime;
+    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
+    var changedLines = [];
+
+    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
+      if (doc.frontier >= cm.display.viewFrom) { // Visible
+        var oldStyles = line.styles;
+        var highlighted = highlightLine(cm, line, state, true);
+        line.styles = highlighted.styles;
+        var oldCls = line.styleClasses, newCls = highlighted.classes;
+        if (newCls) line.styleClasses = newCls;
+        else if (oldCls) line.styleClasses = null;
+        var ischange = !oldStyles || oldStyles.length != line.styles.length ||
+          oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
+        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
+        if (ischange) changedLines.push(doc.frontier);
+        line.stateAfter = copyState(doc.mode, state);
+      } else {
+        processLine(cm, line.text, state);
+        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
+      }
+      ++doc.frontier;
+      if (+new Date > end) {
+        startWorker(cm, cm.options.workDelay);
+        return true;
+      }
+    });
+    if (changedLines.length) runInOp(cm, function() {
+      for (var i = 0; i < changedLines.length; i++)
+        regLineChange(cm, changedLines[i], "text");
+    });
+  }
+
+  // Finds the line to start with when starting a parse. Tries to
+  // find a line with a stateAfter, so that it can start with a
+  // valid state. If that fails, it returns the line with the
+  // smallest indentation, which tends to need the least context to
+  // parse correctly.
+  function findStartLine(cm, n, precise) {
+    var minindent, minline, doc = cm.doc;
+    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
+    for (var search = n; search > lim; --search) {
+      if (search <= doc.first) return doc.first;
+      var line = getLine(doc, search - 1);
+      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
+      var indented = countColumn(line.text, null, cm.options.tabSize);
+      if (minline == null || minindent > indented) {
+        minline = search - 1;
+        minindent = indented;
+      }
+    }
+    return minline;
+  }
+
+  function getStateBefore(cm, n, precise) {
+    var doc = cm.doc, display = cm.display;
+    if (!doc.mode.startState) return true;
+    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
+    if (!state) state = startState(doc.mode);
+    else state = copyState(doc.mode, state);
+    doc.iter(pos, n, function(line) {
+      processLine(cm, line.text, state);
+      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
+      line.stateAfter = save ? copyState(doc.mode, state) : null;
+      ++pos;
+    });
+    if (precise) doc.frontier = pos;
+    return state;
+  }
+
+  // POSITION MEASUREMENT
+
+  function paddingTop(display) {return display.lineSpace.offsetTop;}
+  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
+  function paddingH(display) {
+    if (display.cachedPaddingH) return display.cachedPaddingH;
+    var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
+    var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
+    var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
+    if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
+    return data;
+  }
+
+  function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
+  function displayWidth(cm) {
+    return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
+  }
+  function displayHeight(cm) {
+    return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
+  }
+
+  // Ensure the lineView.wrapping.heights array is populated. This is
+  // an array of bottom offsets for the lines that make up a drawn
+  // line. When lineWrapping is on, there might be more than one
+  // height.
+  function ensureLineHeights(cm, lineView, rect) {
+    var wrapping = cm.options.lineWrapping;
+    var curWidth = wrapping && displayWidth(cm);
+    if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
+      var heights = lineView.measure.heights = [];
+      if (wrapping) {
+        lineView.measure.width = curWidth;
+        var rects = lineView.text.firstChild.getClientRects();
+        for (var i = 0; i < rects.length - 1; i++) {
+          var cur = rects[i], next = rects[i + 1];
+          if (Math.abs(cur.bottom - next.bottom) > 2)
+            heights.push((cur.bottom + next.top) / 2 - rect.top);
+        }
+      }
+      heights.push(rect.bottom - rect.top);
+    }
+  }
+
+  // Find a line map (mapping character offsets to text nodes) and a
+  // measurement cache for the given line number. (A line view might
+  // contain multiple lines when collapsed ranges are present.)
+  function mapFromLineView(lineView, line, lineN) {
+    if (lineView.line == line)
+      return {map: lineView.measure.map, cache: lineView.measure.cache};
+    for (var i = 0; i < lineView.rest.length; i++)
+      if (lineView.rest[i] == line)
+        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
+    for (var i = 0; i < lineView.rest.length; i++)
+      if (lineNo(lineView.rest[i]) > lineN)
+        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
+  }
+
+  // Render a line into the hidden node display.externalMeasured. Used
+  // when measurement is needed for a line that's not in the viewport.
+  function updateExternalMeasurement(cm, line) {
+    line = visualLine(line);
+    var lineN = lineNo(line);
+    var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
+    view.lineN = lineN;
+    var built = view.built = buildLineContent(cm, view);
+    view.text = built.pre;
+    removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
+    return view;
+  }
+
+  // Get a {top, bottom, left, right} box (in line-local coordinates)
+  // for a given character.
+  function measureChar(cm, line, ch, bias) {
+    return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
+  }
+
+  // Find a line view that corresponds to the given line number.
+  function findViewForLine(cm, lineN) {
+    if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
+      return cm.display.view[findViewIndex(cm, lineN)];
+    var ext = cm.display.externalMeasured;
+    if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
+      return ext;
+  }
+
+  // Measurement can be split in two steps, the set-up work that
+  // applies to the whole line, and the measurement of the actual
+  // character. Functions like coordsChar, that need to do a lot of
+  // measurements in a row, can thus ensure that the set-up work is
+  // only done once.
+  function prepareMeasureForLine(cm, line) {
+    var lineN = lineNo(line);
+    var view = findViewForLine(cm, lineN);
+    if (view && !view.text)
+      view = null;
+    else if (view && view.changes)
+      updateLineForChanges(cm, view, lineN, getDimensions(cm));
+    if (!view)
+      view = updateExternalMeasurement(cm, line);
+
+    var info = mapFromLineView(view, line, lineN);
+    return {
+      line: line, view: view, rect: null,
+      map: info.map, cache: info.cache, before: info.before,
+      hasHeights: false
+    };
+  }
+
+  // Given a prepared measurement object, measures the position of an
+  // actual character (or fetches it from the cache).
+  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
+    if (prepared.before) ch = -1;
+    var key = ch + (bias || ""), found;
+    if (prepared.cache.hasOwnProperty(key)) {
+      found = prepared.cache[key];
+    } else {
+      if (!prepared.rect)
+        prepared.rect = prepared.view.text.getBoundingClientRect();
+      if (!prepared.hasHeights) {
+        ensureLineHeights(cm, prepared.view, prepared.rect);
+        prepared.hasHeights = true;
+      }
+      found = measureCharInner(cm, prepared, ch, bias);
+      if (!found.bogus) prepared.cache[key] = found;
+    }
+    return {left: found.left, right: found.right,
+            top: varHeight ? found.rtop : found.top,
+            bottom: varHeight ? found.rbottom : found.bottom};
+  }
+
+  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
+
+  function nodeAndOffsetInLineMap(map, ch, bias) {
+    var node, start, end, collapse;
+    // First, search the line map for the text node corresponding to,
+    // or closest to, the target character.
+    for (var i = 0; i < map.length; i += 3) {
+      var mStart = map[i], mEnd = map[i + 1];
+      if (ch < mStart) {
+        start = 0; end = 1;
+        collapse = "left";
+      } else if (ch < mEnd) {
+        start = ch - mStart;
+        end = start + 1;
+      } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
+        end = mEnd - mStart;
+        start = end - 1;
+        if (ch >= mEnd) collapse = "right";
+      }
+      if (start != null) {
+        node = map[i + 2];
+        if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
+          collapse = bias;
+        if (bias == "left" && start == 0)
+          while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
+            node = map[(i -= 3) + 2];
+            collapse = "left";
+          }
+        if (bias == "right" && start == mEnd - mStart)
+          while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
+            node = map[(i += 3) + 2];
+            collapse = "right";
+          }
+        break;
+      }
+    }
+    return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
+  }
+
+  function measureCharInner(cm, prepared, ch, bias) {
+    var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
+    var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
+
+    var rect;
+    if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
+      for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
+        while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
+        while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
+        if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
+          rect = node.parentNode.getBoundingClientRect();
+        } else if (ie && cm.options.lineWrapping) {
+          var rects = range(node, start, end).getClientRects();
+          if (rects.length)
+            rect = rects[bias == "right" ? rects.length - 1 : 0];
+          else
+            rect = nullRect;
+        } else {
+          rect = range(node, start, end).getBoundingClientRect() || nullRect;
+        }
+        if (rect.left || rect.right || start == 0) break;
+        end = start;
+        start = start - 1;
+        collapse = "right";
+      }
+      if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
+    } else { // If it is a widget, simply get the box for the whole widget.
+      if (start > 0) collapse = bias = "right";
+      var rects;
+      if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
+        rect = rects[bias == "right" ? rects.length - 1 : 0];
+      else
+        rect = node.getBoundingClientRect();
+    }
+    if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
+      var rSpan = node.parentNode.getClientRects()[0];
+      if (rSpan)
+        rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
+      else
+        rect = nullRect;
+    }
+
+    var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
+    var mid = (rtop + rbot) / 2;
+    var heights = prepared.view.measure.heights;
+    for (var i = 0; i < heights.length - 1; i++)
+      if (mid < heights[i]) break;
+    var top = i ? heights[i - 1] : 0, bot = heights[i];
+    var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
+                  right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
+                  top: top, bottom: bot};
+    if (!rect.left && !rect.right) result.bogus = true;
+    if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
+
+    return result;
+  }
+
+  // Work around problem with bounding client rects on ranges being
+  // returned incorrectly when zoomed on IE10 and below.
+  function maybeUpdateRectForZooming(measure, rect) {
+    if (!window.screen || screen.logicalXDPI == null ||
+        screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
+      return rect;
+    var scaleX = screen.logicalXDPI / screen.deviceXDPI;
+    var scaleY = screen.logicalYDPI / screen.deviceYDPI;
+    return {left: rect.left * scaleX, right: rect.right * scaleX,
+            top: rect.top * scaleY, bottom: rect.bottom * scaleY};
+  }
+
+  function clearLineMeasurementCacheFor(lineView) {
+    if (lineView.measure) {
+      lineView.measure.cache = {};
+      lineView.measure.heights = null;
+      if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+        lineView.measure.caches[i] = {};
+    }
+  }
+
+  function clearLineMeasurementCache(cm) {
+    cm.display.externalMeasure = null;
+    removeChildren(cm.display.lineMeasure);
+    for (var i = 0; i < cm.display.view.length; i++)
+      clearLineMeasurementCacheFor(cm.display.view[i]);
+  }
+
+  function clearCaches(cm) {
+    clearLineMeasurementCache(cm);
+    cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
+    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
+    cm.display.lineNumChars = null;
+  }
+
+  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
+  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
+
+  // Converts a {top, bottom, left, right} box from line-local
+  // coordinates into another coordinate system. Context may be one of
+  // "line", "div" (display.lineDiv), "local"/null (editor), "window",
+  // or "page".
+  function intoCoordSystem(cm, lineObj, rect, context) {
+    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
+      var size = widgetHeight(lineObj.widgets[i]);
+      rect.top += size; rect.bottom += size;
+    }
+    if (context == "line") return rect;
+    if (!context) context = "local";
+    var yOff = heightAtLine(lineObj);
+    if (context == "local") yOff += paddingTop(cm.display);
+    else yOff -= cm.display.viewOffset;
+    if (context == "page" || context == "window") {
+      var lOff = cm.display.lineSpace.getBoundingClientRect();
+      yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
+      var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
+      rect.left += xOff; rect.right += xOff;
+    }
+    rect.top += yOff; rect.bottom += yOff;
+    return rect;
+  }
+
+  // Coverts a box from "div" coords to another coordinate system.
+  // Context may be "window", "page", "div", or "local"/null.
+  function fromCoordSystem(cm, coords, context) {
+    if (context == "div") return coords;
+    var left = coords.left, top = coords.top;
+    // First move into "page" coordinate system
+    if (context == "page") {
+      left -= pageScrollX();
+      top -= pageScrollY();
+    } else if (context == "local" || !context) {
+      var localBox = cm.display.sizer.getBoundingClientRect();
+      left += localBox.left;
+      top += localBox.top;
+    }
+
+    var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
+    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
+  }
+
+  function charCoords(cm, pos, context, lineObj, bias) {
+    if (!lineObj) lineObj = getLine(cm.doc, pos.line);
+    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
+  }
+
+  // Returns a box for a given cursor position, which may have an
+  // 'other' property containing the position of the secondary cursor
+  // on a bidi boundary.
+  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
+    lineObj = lineObj || getLine(cm.doc, pos.line);
+    if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
+    function get(ch, right) {
+      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
+      if (right) m.left = m.right; else m.right = m.left;
+      return intoCoordSystem(cm, lineObj, m, context);
+    }
+    function getBidi(ch, partPos) {
+      var part = order[partPos], right = part.level % 2;
+      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
+        part = order[--partPos];
+        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
+        right = true;
+      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
+        part = order[++partPos];
+        ch = bidiLeft(part) - part.level % 2;
+        right = false;
+      }
+      if (right && ch == part.to && ch > part.from) return get(ch - 1);
+      return get(ch, right);
+    }
+    var order = getOrder(lineObj), ch = pos.ch;
+    if (!order) return get(ch);
+    var partPos = getBidiPartAt(order, ch);
+    var val = getBidi(ch, partPos);
+    if (bidiOther != null) val.other = getBidi(ch, bidiOther);
+    return val;
+  }
+
+  // Used to cheaply estimate the coordinates for a position. Used for
+  // intermediate scroll updates.
+  function estimateCoords(cm, pos) {
+    var left = 0, pos = clipPos(cm.doc, pos);
+    if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
+    var lineObj = getLine(cm.doc, pos.line);
+    var top = heightAtLine(lineObj) + paddingTop(cm.display);
+    return {left: left, right: left, top: top, bottom: top + lineObj.height};
+  }
+
+  // Positions returned by coordsChar contain some extra information.
+  // xRel is the relative x position of the input coordinates compared
+  // to the found position (so xRel > 0 means the coordinates are to
+  // the right of the character position, for example). When outside
+  // is true, that means the coordinates lie outside the line's
+  // vertical range.
+  function PosWithInfo(line, ch, outside, xRel) {
+    var pos = Pos(line, ch);
+    pos.xRel = xRel;
+    if (outside) pos.outside = true;
+    return pos;
+  }
+
+  // Compute the character position closest to the given coordinates.
+  // Input must be lineSpace-local ("div" coordinate system).
+  function coordsChar(cm, x, y) {
+    var doc = cm.doc;
+    y += cm.display.viewOffset;
+    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
+    var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
+    if (lineN > last)
+      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
+    if (x < 0) x = 0;
+
+    var lineObj = getLine(doc, lineN);
+    for (;;) {
+      var found = coordsCharInner(cm, lineObj, lineN, x, y);
+      var merged = collapsedSpanAtEnd(lineObj);
+      var mergedPos = merged && merged.find(0, true);
+      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
+        lineN = lineNo(lineObj = mergedPos.to.line);
+      else
+        return found;
+    }
+  }
+
+  function coordsCharInner(cm, lineObj, lineNo, x, y) {
+    var innerOff = y - heightAtLine(lineObj);
+    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
+    var preparedMeasure = prepareMeasureForLine(cm, lineObj);
+
+    function getX(ch) {
+      var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
+      wrongLine = true;
+      if (innerOff > sp.bottom) return sp.left - adjust;
+      else if (innerOff < sp.top) return sp.left + adjust;
+      else wrongLine = false;
+      return sp.left;
+    }
+
+    var bidi = getOrder(lineObj), dist = lineObj.text.length;
+    var from = lineLeft(lineObj), to = lineRight(lineObj);
+    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
+
+    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
+    // Do a binary search between these bounds.
+    for (;;) {
+      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
+        var ch = x < fromX || x - fromX <= toX - x ? from : to;
+        var xDiff = x - (ch == from ? fromX : toX);
+        while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
+        var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
+                              xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
+        return pos;
+      }
+      var step = Math.ceil(dist / 2), middle = from + step;
+      if (bidi) {
+        middle = from;
+        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
+      }
+      var middleX = getX(middle);
+      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
+      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
+    }
+  }
+
+  var measureText;
+  // Compute the default text height.
+  function textHeight(display) {
+    if (display.cachedTextHeight != null) return display.cachedTextHeight;
+    if (measureText == null) {
+      measureText = elt("pre");
+      // Measure a bunch of lines, for browsers that compute
+      // fractional heights.
+      for (var i = 0; i < 49; ++i) {
+        measureText.appendChild(document.createTextNode("x"));
+        measureText.appendChild(elt("br"));
+      }
+      measureText.appendChild(document.createTextNode("x"));
+    }
+    removeChildrenAndAdd(display.measure, measureText);
+    var height = measureText.offsetHeight / 50;
+    if (height > 3) display.cachedTextHeight = height;
+    removeChildren(display.measure);
+    return height || 1;
+  }
+
+  // Compute the default character width.
+  function charWidth(display) {
+    if (display.cachedCharWidth != null) return display.cachedCharWidth;
+    var anchor = elt("span", "xxxxxxxxxx");
+    var pre = elt("pre", [anchor]);
+    removeChildrenAndAdd(display.measure, pre);
+    var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
+    if (width > 2) display.cachedCharWidth = width;
+    return width || 10;
+  }
+
+  // OPERATIONS
+
+  // Operations are used to wrap a series of changes to the editor
+  // state in such a way that each change won't have to update the
+  // cursor and display (which would be awkward, slow, and
+  // error-prone). Instead, display updates are batched and then all
+  // combined and executed at once.
+
+  var operationGroup = null;
+
+  var nextOpId = 0;
+  // Start a new operation.
+  function startOperation(cm) {
+    cm.curOp = {
+      cm: cm,
+      viewChanged: false,      // Flag that indicates that lines might need to be redrawn
+      startHeight: cm.doc.height, // Used to detect need to update scrollbar
+      forceUpdate: false,      // Used to force a redraw
+      updateInput: null,       // Whether to reset the input textarea
+      typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
+      changeObjs: null,        // Accumulated changes, for firing change events
+      cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
+      cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
+      selectionChanged: false, // Whether the selection needs to be redrawn
+      updateMaxLine: false,    // Set when the widest line needs to be determined anew
+      scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
+      scrollToPos: null,       // Used to scroll to a specific position
+      focus: false,
+      id: ++nextOpId           // Unique ID
+    };
+    if (operationGroup) {
+      operationGroup.ops.push(cm.curOp);
+    } else {
+      cm.curOp.ownsGroup = operationGroup = {
+        ops: [cm.curOp],
+        delayedCallbacks: []
+      };
+    }
+  }
+
+  function fireCallbacksForOps(group) {
+    // Calls delayed callbacks and cursorActivity handlers until no
+    // new ones appear
+    var callbacks = group.delayedCallbacks, i = 0;
+    do {
+      for (; i < callbacks.length; i++)
+        callbacks[i]();
+      for (var j = 0; j < group.ops.length; j++) {
+        var op = group.ops[j];
+        if (op.cursorActivityHandlers)
+          while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
+            op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
+      }
+    } while (i < callbacks.length);
+  }
+
+  // Finish an operation, updating the display and signalling delayed events
+  function endOperation(cm) {
+    var op = cm.curOp, group = op.ownsGroup;
+    if (!group) return;
+
+    try { fireCallbacksForOps(group); }
+    finally {
+      operationGroup = null;
+      for (var i = 0; i < group.ops.length; i++)
+        group.ops[i].cm.curOp = null;
+      endOperations(group);
+    }
+  }
+
+  // The DOM updates done when an operation finishes are batched so
+  // that the minimum number of relayouts are required.
+  function endOperations(group) {
+    var ops = group.ops;
+    for (var i = 0; i < ops.length; i++) // Read DOM
+      endOperation_R1(ops[i]);
+    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+      endOperation_W1(ops[i]);
+    for (var i = 0; i < ops.length; i++) // Read DOM
+      endOperation_R2(ops[i]);
+    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+      endOperation_W2(ops[i]);
+    for (var i = 0; i < ops.length; i++) // Read DOM
+      endOperation_finish(ops[i]);
+  }
+
+  function endOperation_R1(op) {
+    var cm = op.cm, display = cm.display;
+    maybeClipScrollbars(cm);
+    if (op.updateMaxLine) findMaxLine(cm);
+
+    op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
+      op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
+                         op.scrollToPos.to.line >= display.viewTo) ||
+      display.maxLineChanged && cm.options.lineWrapping;
+    op.update = op.mustUpdate &&
+      new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
+  }
+
+  function endOperation_W1(op) {
+    op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
+  }
+
+  function endOperation_R2(op) {
+    var cm = op.cm, display = cm.display;
+    if (op.updatedDisplay) updateHeightsInViewport(cm);
+
+    op.barMeasure = measureForScrollbars(cm);
+
+    // If the max line changed since it was last measured, measure it,
+    // and ensure the document's width matches it.
+    // updateDisplay_W2 will use these properties to do the actual resizing
+    if (display.maxLineChanged && !cm.options.lineWrapping) {
+      op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
+      cm.display.sizerWidth = op.adjustWidthTo;
+      op.barMeasure.scrollWidth =
+        Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
+      op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
+    }
+
+    if (op.updatedDisplay || op.selectionChanged)
+      op.preparedSelection = display.input.prepareSelection();
+  }
+
+  function endOperation_W2(op) {
+    var cm = op.cm;
+
+    if (op.adjustWidthTo != null) {
+      cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
+      if (op.maxScrollLeft < cm.doc.scrollLeft)
+        setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
+      cm.display.maxLineChanged = false;
+    }
+
+    if (op.preparedSelection)
+      cm.display.input.showSelection(op.preparedSelection);
+    if (op.updatedDisplay)
+      setDocumentHeight(cm, op.barMeasure);
+    if (op.updatedDisplay || op.startHeight != cm.doc.height)
+      updateScrollbars(cm, op.barMeasure);
+
+    if (op.selectionChanged) restartBlink(cm);
+
+    if (cm.state.focused && op.updateInput)
+      cm.display.input.reset(op.typing);
+    if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
+  }
+
+  function endOperation_finish(op) {
+    var cm = op.cm, display = cm.display, doc = cm.doc;
+
+    if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
+
+    // Abort mouse wheel delta measurement, when scrolling explicitly
+    if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
+      display.wheelStartX = display.wheelStartY = null;
+
+    // Propagate the scroll position to the actual DOM scroller
+    if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
+      doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
+      display.scrollbars.setScrollTop(doc.scrollTop);
+      display.scroller.scrollTop = doc.scrollTop;
+    }
+    if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
+      doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
+      display.scrollbars.setScrollLeft(doc.scrollLeft);
+      display.scroller.scrollLeft = doc.scrollLeft;
+      alignHorizontally(cm);
+    }
+    // If we need to scroll a specific position into view, do so.
+    if (op.scrollToPos) {
+      var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
+                                     clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
+      if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
+    }
+
+    // Fire events for markers that are hidden/unidden by editing or
+    // undoing
+    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
+    if (hidden) for (var i = 0; i < hidden.length; ++i)
+      if (!hidden[i].lines.length) signal(hidden[i], "hide");
+    if (unhidden) for (var i = 0; i < unhidden.length; ++i)
+      if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
+
+    if (display.wrapper.offsetHeight)
+      doc.scrollTop = cm.display.scroller.scrollTop;
+
+    // Fire change events, and delayed event handlers
+    if (op.changeObjs)
+      signal(cm, "changes", cm, op.changeObjs);
+    if (op.update)
+      op.update.finish();
+  }
+
+  // Run the given function in an operation
+  function runInOp(cm, f) {
+    if (cm.curOp) return f();
+    startOperation(cm);
+    try { return f(); }
+    finally { endOperation(cm); }
+  }
+  // Wraps a function in an operation. Returns the wrapped function.
+  function operation(cm, f) {
+    return function() {
+      if (cm.curOp) return f.apply(cm, arguments);
+      startOperation(cm);
+      try { return f.apply(cm, arguments); }
+      finally { endOperation(cm); }
+    };
+  }
+  // Used to add methods to editor and doc instances, wrapping them in
+  // operations.
+  function methodOp(f) {
+    return function() {
+      if (this.curOp) return f.apply(this, arguments);
+      startOperation(this);
+      try { return f.apply(this, arguments); }
+      finally { endOperation(this); }
+    };
+  }
+  function docMethodOp(f) {
+    return function() {
+      var cm = this.cm;
+      if (!cm || cm.curOp) return f.apply(this, arguments);
+      startOperation(cm);
+      try { return f.apply(this, arguments); }
+      finally { endOperation(cm); }
+    };
+  }
+
+  // VIEW TRACKING
+
+  // These objects are used to represent the visible (currently drawn)
+  // part of the document. A LineView may correspond to multiple
+  // logical lines, if those are connected by collapsed ranges.
+  function LineView(doc, line, lineN) {
+    // The starting line
+    this.line = line;
+    // Continuing lines, if any
+    this.rest = visualLineContinued(line);
+    // Number of logical lines in this visual line
+    this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
+    this.node = this.text = null;
+    this.hidden = lineIsHidden(doc, line);
+  }
+
+  // Create a range of LineView objects for the given lines.
+  function buildViewArray(cm, from, to) {
+    var array = [], nextPos;
+    for (var pos = from; pos < to; pos = nextPos) {
+      var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
+      nextPos = pos + view.size;
+      array.push(view);
+    }
+    return array;
+  }
+
+  // Updates the display.view data structure for a given change to the
+  // document. From and to are in pre-change coordinates. Lendiff is
+  // the amount of lines added or subtracted by the change. This is
+  // used for changes that span multiple lines, or change the way
+  // lines are divided into visual lines. regLineChange (below)
+  // registers single-line changes.
+  function regChange(cm, from, to, lendiff) {
+    if (from == null) from = cm.doc.first;
+    if (to == null) to = cm.doc.first + cm.doc.size;
+    if (!lendiff) lendiff = 0;
+
+    var display = cm.display;
+    if (lendiff && to < display.viewTo &&
+        (display.updateLineNumbers == null || display.updateLineNumbers > from))
+      display.updateLineNumbers = from;
+
+    cm.curOp.viewChanged = true;
+
+    if (from >= display.viewTo) { // Change after
+      if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
+        resetView(cm);
+    } else if (to <= display.viewFrom) { // Change before
+      if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
+        resetView(cm);
+      } else {
+        display.viewFrom += lendiff;
+        display.viewTo += lendiff;
+      }
+    } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
+      resetView(cm);
+    } else if (from <= display.viewFrom) { // Top overlap
+      var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
+      if (cut) {
+        display.view = display.view.slice(cut.index);
+        display.viewFrom = cut.lineN;
+        display.viewTo += lendiff;
+      } else {
+        resetView(cm);
+      }
+    } else if (to >= display.viewTo) { // Bottom overlap
+      var cut = viewCuttingPoint(cm, from, from, -1);
+      if (cut) {
+        display.view = display.view.slice(0, cut.index);
+        display.viewTo = cut.lineN;
+      } else {
+        resetView(cm);
+      }
+    } else { // Gap in the middle
+      var cutTop = viewCuttingPoint(cm, from, from, -1);
+      var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
+      if (cutTop && cutBot) {
+        display.view = display.view.slice(0, cutTop.index)
+          .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
+          .concat(display.view.slice(cutBot.index));
+        display.viewTo += lendiff;
+      } else {
+        resetView(cm);
+      }
+    }
+
+    var ext = display.externalMeasured;
+    if (ext) {
+      if (to < ext.lineN)
+        ext.lineN += lendiff;
+      else if (from < ext.lineN + ext.size)
+        display.externalMeasured = null;
+    }
+  }
+
+  // Register a change to a single line. Type must be one of "text",
+  // "gutter", "class", "widget"
+  function regLineChange(cm, line, type) {
+    cm.curOp.viewChanged = true;
+    var display = cm.display, ext = cm.display.externalMeasured;
+    if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
+      display.externalMeasured = null;
+
+    if (line < display.viewFrom || line >= display.viewTo) return;
+    var lineView = display.view[findViewIndex(cm, line)];
+    if (lineView.node == null) return;
+    var arr = lineView.changes || (lineView.changes = []);
+    if (indexOf(arr, type) == -1) arr.push(type);
+  }
+
+  // Clear the view.
+  function resetView(cm) {
+    cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
+    cm.display.view = [];
+    cm.display.viewOffset = 0;
+  }
+
+  // Find the view element corresponding to a given line. Return null
+  // when the line isn't visible.
+  function findViewIndex(cm, n) {
+    if (n >= cm.display.viewTo) return null;
+    n -= cm.display.viewFrom;
+    if (n < 0) return null;
+    var view = cm.display.view;
+    for (var i = 0; i < view.length; i++) {
+      n -= view[i].size;
+      if (n < 0) return i;
+    }
+  }
+
+  function viewCuttingPoint(cm, oldN, newN, dir) {
+    var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
+    if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
+      return {index: index, lineN: newN};
+    for (var i = 0, n = cm.display.viewFrom; i < index; i++)
+      n += view[i].size;
+    if (n != oldN) {
+      if (dir > 0) {
+        if (index == view.length - 1) return null;
+        diff = (n + view[index].size) - oldN;
+        index++;
+      } else {
+        diff = n - oldN;
+      }
+      oldN += diff; newN += diff;
+    }
+    while (visualLineNo(cm.doc, newN) != newN) {
+      if (index == (dir < 0 ? 0 : view.length - 1)) return null;
+      newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
+      index += dir;
+    }
+    return {index: index, lineN: newN};
+  }
+
+  // Force the view to cover a given range, adding empty view element
+  // or clipping off existing ones as needed.
+  function adjustView(cm, from, to) {
+    var display = cm.display, view = display.view;
+    if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
+      display.view = buildViewArray(cm, from, to);
+      display.viewFrom = from;
+    } else {
+      if (display.viewFrom > from)
+        display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
+      else if (display.viewFrom < from)
+        display.view = display.view.slice(findViewIndex(cm, from));
+      display.viewFrom = from;
+      if (display.viewTo < to)
+        display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
+      else if (display.viewTo > to)
+        display.view = display.view.slice(0, findViewIndex(cm, to));
+    }
+    display.viewTo = to;
+  }
+
+  // Count the number of lines in the view whose DOM representation is
+  // out of date (or nonexistent).
+  function countDirtyView(cm) {
+    var view = cm.display.view, dirty = 0;
+    for (var i = 0; i < view.length; i++) {
+      var lineView = view[i];
+      if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
+    }
+    return dirty;
+  }
+
+  // EVENT HANDLERS
+
+  // Attach the necessary event handlers when initializing the editor
+  function registerEventHandlers(cm) {
+    var d = cm.display;
+    on(d.scroller, "mousedown", operation(cm, onMouseDown));
+    // Older IE's will not fire a second mousedown for a double click
+    if (ie && ie_version < 11)
+      on(d.scroller, "dblclick", operation(cm, function(e) {
+        if (signalDOMEvent(cm, e)) return;
+        var pos = posFromMouse(cm, e);
+        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
+        e_preventDefault(e);
+        var word = cm.findWordAt(pos);
+        extendSelection(cm.doc, word.anchor, word.head);
+      }));
+    else
+      on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
+    // Some browsers fire contextmenu *after* opening the menu, at
+    // which point we can't mess with it anymore. Context menu is
+    // handled in onMouseDown for these browsers.
+    if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
+
+    // Used to suppress mouse event handling when a touch happens
+    var touchFinished, prevTouch = {end: 0};
+    function finishTouch() {
+      if (d.activeTouch) {
+        touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
+        prevTouch = d.activeTouch;
+        prevTouch.end = +new Date;
+      }
+    };
+    function isMouseLikeTouchEvent(e) {
+      if (e.touches.length != 1) return false;
+      var touch = e.touches[0];
+      return touch.radiusX <= 1 && touch.radiusY <= 1;
+    }
+    function farAway(touch, other) {
+      if (other.left == null) return true;
+      var dx = other.left - touch.left, dy = other.top - touch.top;
+      return dx * dx + dy * dy > 20 * 20;
+    }
+    on(d.scroller, "touchstart", function(e) {
+      if (!isMouseLikeTouchEvent(e)) {
+        clearTimeout(touchFinished);
+        var now = +new Date;
+        d.activeTouch = {start: now, moved: false,
+                         prev: now - prevTouch.end <= 300 ? prevTouch : null};
+        if (e.touches.length == 1) {
+          d.activeTouch.left = e.touches[0].pageX;
+          d.activeTouch.top = e.touches[0].pageY;
+        }
+      }
+    });
+    on(d.scroller, "touchmove", function() {
+      if (d.activeTouch) d.activeTouch.moved = true;
+    });
+    on(d.scroller, "touchend", function(e) {
+      var touch = d.activeTouch;
+      if (touch && !eventInWidget(d, e) && touch.left != null &&
+          !touch.moved && new Date - touch.start < 300) {
+        var pos = cm.coordsChar(d.activeTouch, "page"), range;
+        if (!touch.prev || farAway(touch, touch.prev)) // Single tap
+          range = new Range(pos, pos);
+        else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
+          range = cm.findWordAt(pos);
+        else // Triple tap
+          range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
+        cm.setSelection(range.anchor, range.head);
+        cm.focus();
+        e_preventDefault(e);
+      }
+      finishTouch();
+    });
+    on(d.scroller, "touchcancel", finishTouch);
+
+    // Sync scrolling between fake scrollbars and real scrollable
+    // area, ensure viewport is updated when scrolling.
+    on(d.scroller, "scroll", function() {
+      if (d.scroller.clientHeight) {
+        setScrollTop(cm, d.scroller.scrollTop);
+        setScrollLeft(cm, d.scroller.scrollLeft, true);
+        signal(cm, "scroll", cm);
+      }
+    });
+
+    // Listen to wheel events in order to try and update the viewport on time.
+    on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
+    on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
+
+    // Prevent wrapper from ever scrolling
+    on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
+
+    d.dragFunctions = {
+      simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
+      start: function(e){onDragStart(cm, e);},
+      drop: operation(cm, onDrop)
+    };
+
+    var inp = d.input.getField();
+    on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
+    on(inp, "keydown", operation(cm, onKeyDown));
+    on(inp, "keypress", operation(cm, onKeyPress));
+    on(inp, "focus", bind(onFocus, cm));
+    on(inp, "blur", bind(onBlur, cm));
+  }
+
+  function dragDropChanged(cm, value, old) {
+    var wasOn = old && old != CodeMirror.Init;
+    if (!value != !wasOn) {
+      var funcs = cm.display.dragFunctions;
+      var toggle = value ? on : off;
+      toggle(cm.display.scroller, "dragstart", funcs.start);
+      toggle(cm.display.scroller, "dragenter", funcs.simple);
+      toggle(cm.display.scroller, "dragover", funcs.simple);
+      toggle(cm.display.scroller, "drop", funcs.drop);
+    }
+  }
+
+  // Called when the window resizes
+  function onResize(cm) {
+    var d = cm.display;
+    if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
+      return;
+    // Might be a text scaling operation, clear size caches.
+    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+    d.scrollbarsClipped = false;
+    cm.setSize();
+  }
+
+  // MOUSE EVENTS
+
+  // Return true when the given mouse event happened in a widget
+  function eventInWidget(display, e) {
+    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
+      if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
+          (n.parentNode == display.sizer && n != display.mover))
+        return true;
+    }
+  }
+
+  // Given a mouse event, find the corresponding position. If liberal
+  // is false, it checks whether a gutter or scrollbar was clicked,
+  // and returns null if it was. forRect is used by rectangular
+  // selections, and tries to estimate a character position even for
+  // coordinates beyond the right of the text.
+  function posFromMouse(cm, e, liberal, forRect) {
+    var display = cm.display;
+    if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
+
+    var x, y, space = display.lineSpace.getBoundingClientRect();
+    // Fails unpredictably on IE[67] when mouse is dragged around quickly.
+    try { x = e.clientX - space.left; y = e.clientY - space.top; }
+    catch (e) { return null; }
+    var coords = coordsChar(cm, x, y), line;
+    if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
+      var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
+      coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
+    }
+    return coords;
+  }
+
+  // A mouse down can be a single click, double click, triple click,
+  // start of selection drag, start of text drag, new cursor
+  // (ctrl-click), rectangle drag (alt-drag), or xwin
+  // middle-click-paste. Or it might be a click on something we should
+  // not interfere with, such as a scrollbar or widget.
+  function onMouseDown(e) {
+    var cm = this, display = cm.display;
+    if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
+    display.shift = e.shiftKey;
+
+    if (eventInWidget(display, e)) {
+      if (!webkit) {
+        // Briefly turn off draggability, to allow widgets to do
+        // normal dragging things.
+        display.scroller.draggable = false;
+        setTimeout(function(){display.scroller.draggable = true;}, 100);
+      }
+      return;
+    }
+    if (clickInGutter(cm, e)) return;
+    var start = posFromMouse(cm, e);
+    window.focus();
+
+    switch (e_button(e)) {
+    case 1:
+      if (start)
+        leftButtonDown(cm, e, start);
+      else if (e_target(e) == display.scroller)
+        e_preventDefault(e);
+      break;
+    case 2:
+      if (webkit) cm.state.lastMiddleDown = +new Date;
+      if (start) extendSelection(cm.doc, start);
+      setTimeout(function() {display.input.focus();}, 20);
+      e_preventDefault(e);
+      break;
+    case 3:
+      if (captureRightClick) onContextMenu(cm, e);
+      else delayBlurEvent(cm);
+      break;
+    }
+  }
+
+  var lastClick, lastDoubleClick;
+  function leftButtonDown(cm, e, start) {
+    if (ie) setTimeout(bind(ensureFocus, cm), 0);
+    else cm.curOp.focus = activeElt();
+
+    var now = +new Date, type;
+    if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
+      type = "triple";
+    } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
+      type = "double";
+      lastDoubleClick = {time: now, pos: start};
+    } else {
+      type = "single";
+      lastClick = {time: now, pos: start};
+    }
+
+    var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
+    if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
+        type == "single" && (contained = sel.contains(start)) > -1 &&
+        (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
+        (cmp(contained.to(), start) > 0 || start.xRel < 0))
+      leftButtonStartDrag(cm, e, start, modifier);
+    else
+      leftButtonSelect(cm, e, start, type, modifier);
+  }
+
+  // Start a text drag. When it ends, see if any dragging actually
+  // happen, and treat as a click if it didn't.
+  function leftButtonStartDrag(cm, e, start, modifier) {
+    var display = cm.display, startTime = +new Date;
+    var dragEnd = operation(cm, function(e2) {
+      if (webkit) display.scroller.draggable = false;
+      cm.state.draggingText = false;
+      off(document, "mouseup", dragEnd);
+      off(display.scroller, "drop", dragEnd);
+      if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
+        e_preventDefault(e2);
+        if (!modifier && +new Date - 200 < startTime)
+          extendSelection(cm.doc, start);
+        // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
+        if (webkit || ie && ie_version == 9)
+          setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
+        else
+          display.input.focus();
+      }
+    });
+    // Let the drag handler handle this.
+    if (webkit) display.scroller.draggable = true;
+    cm.state.draggingText = dragEnd;
+    // IE's approach to draggable
+    if (display.scroller.dragDrop) display.scroller.dragDrop();
+    on(document, "mouseup", dragEnd);
+    on(display.scroller, "drop", dragEnd);
+  }
+
+  // Normal selection, as opposed to text dragging.
+  function leftButtonSelect(cm, e, start, type, addNew) {
+    var display = cm.display, doc = cm.doc;
+    e_preventDefault(e);
+
+    var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
+    if (addNew && !e.shiftKey) {
+      ourIndex = doc.sel.contains(start);
+      if (ourIndex > -1)
+        ourRange = ranges[ourIndex];
+      else
+        ourRange = new Range(start, start);
+    } else {
+      ourRange = doc.sel.primary();
+      ourIndex = doc.sel.primIndex;
+    }
+
+    if (e.altKey) {
+      type = "rect";
+      if (!addNew) ourRange = new Range(start, start);
+      start = posFromMouse(cm, e, true, true);
+      ourIndex = -1;
+    } else if (type == "double") {
+      var word = cm.findWordAt(start);
+      if (cm.display.shift || doc.extend)
+        ourRange = extendRange(doc, ourRange, word.anchor, word.head);
+      else
+        ourRange = word;
+    } else if (type == "triple") {
+      var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
+      if (cm.display.shift || doc.extend)
+        ourRange = extendRange(doc, ourRange, line.anchor, line.head);
+      else
+        ourRange = line;
+    } else {
+      ourRange = extendRange(doc, ourRange, start);
+    }
+
+    if (!addNew) {
+      ourIndex = 0;
+      setSelection(doc, new Selection([ourRange], 0), sel_mouse);
+      startSel = doc.sel;
+    } else if (ourIndex == -1) {
+      ourIndex = ranges.length;
+      setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
+                   {scroll: false, origin: "*mouse"});
+    } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
+      setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
+      startSel = doc.sel;
+    } else {
+      replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
+    }
+
+    var lastPos = start;
+    function extendTo(pos) {
+      if (cmp(lastPos, pos) == 0) return;
+      lastPos = pos;
+
+      if (type == "rect") {
+        var ranges = [], tabSize = cm.options.tabSize;
+        var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
+        var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
+        var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
+        for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
+             line <= end; line++) {
+          var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
+          if (left == right)
+            ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
+          else if (text.length > leftPos)
+            ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
+        }
+        if (!ranges.length) ranges.push(new Range(start, start));
+        setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
+                     {origin: "*mouse", scroll: false});
+        cm.scrollIntoView(pos);
+      } else {
+        var oldRange = ourRange;
+        var anchor = oldRange.anchor, head = pos;
+        if (type != "single") {
+          if (type == "double")
+            var range = cm.findWordAt(pos);
+          else
+            var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
+          if (cmp(range.anchor, anchor) > 0) {
+            head = range.head;
+            anchor = minPos(oldRange.from(), range.anchor);
+          } else {
+            head = range.anchor;
+            anchor = maxPos(oldRange.to(), range.head);
+          }
+        }
+        var ranges = startSel.ranges.slice(0);
+        ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
+        setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
+      }
+    }
+
+    var editorSize = display.wrapper.getBoundingClientRect();
+    // Used to ensure timeout re-tries don't fire when another extend
+    // happened in the meantime (clearTimeout isn't reliable -- at
+    // least on Chrome, the timeouts still happen even when cleared,
+    // if the clear happens after their scheduled firing time).
+    var counter = 0;
+
+    function extend(e) {
+      var curCount = ++counter;
+      var cur = posFromMouse(cm, e, true, type == "rect");
+      if (!cur) return;
+      if (cmp(cur, lastPos) != 0) {
+        cm.curOp.focus = activeElt();
+        extendTo(cur);
+        var visible = visibleLines(display, doc);
+        if (cur.line >= visible.to || cur.line < visible.from)
+          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
+      } else {
+        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
+        if (outside) setTimeout(operation(cm, function() {
+          if (counter != curCount) return;
+          display.scroller.scrollTop += outside;
+          extend(e);
+        }), 50);
+      }
+    }
+
+    function done(e) {
+      counter = Infinity;
+      e_preventDefault(e);
+      display.input.focus();
+      off(document, "mousemove", move);
+      off(document, "mouseup", up);
+      doc.history.lastSelOrigin = null;
+    }
+
+    var move = operation(cm, function(e) {
+      if (!e_button(e)) done(e);
+      else extend(e);
+    });
+    var up = operation(cm, done);
+    on(document, "mousemove", move);
+    on(document, "mouseup", up);
+  }
+
+  // Determines whether an event happened in the gutter, and fires the
+  // handlers for the corresponding event.
+  function gutterEvent(cm, e, type, prevent, signalfn) {
+    try { var mX = e.clientX, mY = e.clientY; }
+    catch(e) { return false; }
+    if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
+    if (prevent) e_preventDefault(e);
+
+    var display = cm.display;
+    var lineBox = display.lineDiv.getBoundingClientRect();
+
+    if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
+    mY -= lineBox.top - display.viewOffset;
+
+    for (var i = 0; i < cm.options.gutters.length; ++i) {
+      var g = display.gutters.childNodes[i];
+      if (g && g.getBoundingClientRect().right >= mX) {
+        var line = lineAtHeight(cm.doc, mY);
+        var gutter = cm.options.gutters[i];
+        signalfn(cm, type, cm, line, gutter, e);
+        return e_defaultPrevented(e);
+      }
+    }
+  }
+
+  function clickInGutter(cm, e) {
+    return gutterEvent(cm, e, "gutterClick", true, signalLater);
+  }
+
+  // Kludge to work around strange IE behavior where it'll sometimes
+  // re-fire a series of drag-related events right after the drop (#1551)
+  var lastDrop = 0;
+
+  function onDrop(e) {
+    var cm = this;
+    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
+      return;
+    e_preventDefault(e);
+    if (ie) lastDrop = +new Date;
+    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
+    if (!pos || isReadOnly(cm)) return;
+    // Might be a file drop, in which case we simply extract the text
+    // and insert it.
+    if (files && files.length && window.FileReader && window.File) {
+      var n = files.length, text = Array(n), read = 0;
+      var loadFile = function(file, i) {
+        var reader = new FileReader;
+        reader.onload = operation(cm, function() {
+          text[i] = reader.result;
+          if (++read == n) {
+            pos = clipPos(cm.doc, pos);
+            var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
+            makeChange(cm.doc, change);
+            setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
+          }
+        });
+        reader.readAsText(file);
+      };
+      for (var i = 0; i < n; ++i) loadFile(files[i], i);
+    } else { // Normal drop
+      // Don't do a replace if the drop happened inside of the selected text.
+      if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
+        cm.state.draggingText(e);
+        // Ensure the editor is re-focused
+        setTimeout(function() {cm.display.input.focus();}, 20);
+        return;
+      }
+      try {
+        var text = e.dataTransfer.getData("Text");
+        if (text) {
+          if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
+            var selected = cm.listSelections();
+          setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
+          if (selected) for (var i = 0; i < selected.length; ++i)
+            replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
+          cm.replaceSelection(text, "around", "paste");
+          cm.display.input.focus();
+        }
+      }
+      catch(e){}
+    }
+  }
+
+  function onDragStart(cm, e) {
+    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
+    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
+
+    e.dataTransfer.setData("Text", cm.getSelection());
+
+    // Use dummy image instead of default browsers image.
+    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
+    if (e.dataTransfer.setDragImage && !safari) {
+      var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+      img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
+      if (presto) {
+        img.width = img.height = 1;
+        cm.display.wrapper.appendChild(img);
+        // Force a relayout, or Opera won't use our image for some obscure reason
+        img._top = img.offsetTop;
+      }
+      e.dataTransfer.setDragImage(img, 0, 0);
+      if (presto) img.parentNode.removeChild(img);
+    }
+  }
+
+  // SCROLL EVENTS
+
+  // Sync the scrollable area and scrollbars, ensure the viewport
+  // covers the visible area.
+  function setScrollTop(cm, val) {
+    if (Math.abs(cm.doc.scrollTop - val) < 2) return;
+    cm.doc.scrollTop = val;
+    if (!gecko) updateDisplaySimple(cm, {top: val});
+    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
+    cm.display.scrollbars.setScrollTop(val);
+    if (gecko) updateDisplaySimple(cm);
+    startWorker(cm, 100);
+  }
+  // Sync scroller and scrollbar, ensure the gutter elements are
+  // aligned.
+  function setScrollLeft(cm, val, isScroller) {
+    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
+    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
+    cm.doc.scrollLeft = val;
+    alignHorizontally(cm);
+    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
+    cm.display.scrollbars.setScrollLeft(val);
+  }
+
+  // Since the delta values reported on mouse wheel events are
+  // unstandardized between browsers and even browser versions, and
+  // generally horribly unpredictable, this code starts by measuring
+  // the scroll effect that the first few mouse wheel events have,
+  // and, from that, detects the way it can convert deltas to pixel
+  // offsets afterwards.
+  //
+  // The reason we want to know the amount a wheel event will scroll
+  // is that it gives us a chance to update the display before the
+  // actual scrolling happens, reducing flickering.
+
+  var wheelSamples = 0, wheelPixelsPerUnit = null;
+  // Fill in a browser-detected starting value on browsers where we
+  // know one. These don't have to be accurate -- the result of them
+  // being wrong would just be a slight flicker on the first wheel
+  // scroll (if it is large enough).
+  if (ie) wheelPixelsPerUnit = -.53;
+  else if (gecko) wheelPixelsPerUnit = 15;
+  else if (chrome) wheelPixelsPerUnit = -.7;
+  else if (safari) wheelPixelsPerUnit = -1/3;
+
+  var wheelEventDelta = function(e) {
+    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
+    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
+    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
+    else if (dy == null) dy = e.wheelDelta;
+    return {x: dx, y: dy};
+  };
+  CodeMirror.wheelEventPixels = function(e) {
+    var delta = wheelEventDelta(e);
+    delta.x *= wheelPixelsPerUnit;
+    delta.y *= wheelPixelsPerUnit;
+    return delta;
+  };
+
+  function onScrollWheel(cm, e) {
+    var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
+
+    var display = cm.display, scroll = display.scroller;
+    // Quit if there's nothing to scroll here
+    if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
+          dy && scroll.scrollHeight > scroll.clientHeight)) return;
+
+    // Webkit browsers on OS X abort momentum scrolls when the target
+    // of the scroll event is removed from the scrollable element.
+    // This hack (see related code in patchDisplay) makes sure the
+    // element is kept around.
+    if (dy && mac && webkit) {
+      outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
+        for (var i = 0; i < view.length; i++) {
+          if (view[i].node == cur) {
+            cm.display.currentWheelTarget = cur;
+            break outer;
+          }
+        }
+      }
+    }
+
+    // On some browsers, horizontal scrolling will cause redraws to
+    // happen before the gutter has been realigned, causing it to
+    // wriggle around in a most unseemly way. When we have an
+    // estimated pixels/delta value, we just handle horizontal
+    // scrolling entirely here. It'll be slightly off from native, but
+    // better than glitching out.
+    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
+      if (dy)
+        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
+      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
+      e_preventDefault(e);
+      display.wheelStartX = null; // Abort measurement, if in progress
+      return;
+    }
+
+    // 'Project' the visible viewport to cover the area that is being
+    // scrolled into view (if we know enough to estimate it).
+    if (dy && wheelPixelsPerUnit != null) {
+      var pixels = dy * wheelPixelsPerUnit;
+      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
+      if (pixels < 0) top = Math.max(0, top + pixels - 50);
+      else bot = Math.min(cm.doc.height, bot + pixels + 50);
+      updateDisplaySimple(cm, {top: top, bottom: bot});
+    }
+
+    if (wheelSamples < 20) {
+      if (display.wheelStartX == null) {
+        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
+        display.wheelDX = dx; display.wheelDY = dy;
+        setTimeout(function() {
+          if (display.wheelStartX == null) return;
+          var movedX = scroll.scrollLeft - display.wheelStartX;
+          var movedY = scroll.scrollTop - display.wheelStartY;
+          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+            (movedX && display.wheelDX && movedX / display.wheelDX);
+          display.wheelStartX = display.wheelStartY = null;
+          if (!sample) return;
+          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
+          ++wheelSamples;
+        }, 200);
+      } else {
+        display.wheelDX += dx; display.wheelDY += dy;
+      }
+    }
+  }
+
+  // KEY EVENTS
+
+  // Run a handler that was bound to a key.
+  function doHandleBinding(cm, bound, dropShift) {
+    if (typeof bound == "string") {
+      bound = commands[bound];
+      if (!bound) return false;
+    }
+    // Ensure previous input has been read, so that the handler sees a
+    // consistent view of the document
+    cm.display.input.ensurePolled();
+    var prevShift = cm.display.shift, done = false;
+    try {
+      if (isReadOnly(cm)) cm.state.suppressEdits = true;
+      if (dropShift) cm.display.shift = false;
+      done = bound(cm) != Pass;
+    } finally {
+      cm.display.shift = prevShift;
+      cm.state.suppressEdits = false;
+    }
+    return done;
+  }
+
+  function lookupKeyForEditor(cm, name, handle) {
+    for (var i = 0; i < cm.state.keyMaps.length; i++) {
+      var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
+      if (result) return result;
+    }
+    return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
+      || lookupKey(name, cm.options.keyMap, handle, cm);
+  }
+
+  var stopSeq = new Delayed;
+  function dispatchKey(cm, name, e, handle) {
+    var seq = cm.state.keySeq;
+    if (seq) {
+      if (isModifierKey(name)) return "handled";
+      stopSeq.set(50, function() {
+        if (cm.state.keySeq == seq) {
+          cm.state.keySeq = null;
+          cm.display.input.reset();
+        }
+      });
+      name = seq + " " + name;
+    }
+    var result = lookupKeyForEditor(cm, name, handle);
+
+    if (result == "multi")
+      cm.state.keySeq = name;
+    if (result == "handled")
+      signalLater(cm, "keyHandled", cm, name, e);
+
+    if (result == "handled" || result == "multi") {
+      e_preventDefault(e);
+      restartBlink(cm);
+    }
+
+    if (seq && !result && /\'$/.test(name)) {
+      e_preventDefault(e);
+      return true;
+    }
+    return !!result;
+  }
+
+  // Handle a key from the keydown event.
+  function handleKeyBinding(cm, e) {
+    var name = keyName(e, true);
+    if (!name) return false;
+
+    if (e.shiftKey && !cm.state.keySeq) {
+      // First try to resolve full name (including 'Shift-'). Failing
+      // that, see if there is a cursor-motion command (starting with
+      // 'go') bound to the keyname without 'Shift-'.
+      return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
+          || dispatchKey(cm, name, e, function(b) {
+               if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
+                 return doHandleBinding(cm, b);
+             });
+    } else {
+      return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
+    }
+  }
+
+  // Handle a key from the keypress event
+  function handleCharBinding(cm, e, ch) {
+    return dispatchKey(cm, "'" + ch + "'", e,
+                       function(b) { return doHandleBinding(cm, b, true); });
+  }
+
+  var lastStoppedKey = null;
+  function onKeyDown(e) {
+    var cm = this;
+    cm.curOp.focus = activeElt();
+    if (signalDOMEvent(cm, e)) return;
+    // IE does strange things with escape.
+    if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
+    var code = e.keyCode;
+    cm.display.shift = code == 16 || e.shiftKey;
+    var handled = handleKeyBinding(cm, e);
+    if (presto) {
+      lastStoppedKey = handled ? code : null;
+      // Opera has no cut event... we try to at least catch the key combo
+      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
+        cm.replaceSelection("", null, "cut");
+    }
+
+    // Turn mouse into crosshair when Alt is held on Mac.
+    if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
+      showCrossHair(cm);
+  }
+
+  function showCrossHair(cm) {
+    var lineDiv = cm.display.lineDiv;
+    addClass(lineDiv, "CodeMirror-crosshair");
+
+    function up(e) {
+      if (e.keyCode == 18 || !e.altKey) {
+        rmClass(lineDiv, "CodeMirror-crosshair");
+        off(document, "keyup", up);
+        off(document, "mouseover", up);
+      }
+    }
+    on(document, "keyup", up);
+    on(document, "mouseover", up);
+  }
+
+  function onKeyUp(e) {
+    if (e.keyCode == 16) this.doc.sel.shift = false;
+    signalDOMEvent(this, e);
+  }
+
+  function onKeyPress(e) {
+    var cm = this;
+    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
+    var keyCode = e.keyCode, charCode = e.charCode;
+    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
+    if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
+    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+    if (handleCharBinding(cm, e, ch)) return;
+    cm.display.input.onKeyPress(e);
+  }
+
+  // FOCUS/BLUR EVENTS
+
+  function delayBlurEvent(cm) {
+    cm.state.delayingBlurEvent = true;
+    setTimeout(function() {
+      if (cm.state.delayingBlurEvent) {
+        cm.state.delayingBlurEvent = false;
+        onBlur(cm);
+      }
+    }, 100);
+  }
+
+  function onFocus(cm) {
+    if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
+
+    if (cm.options.readOnly == "nocursor") return;
+    if (!cm.state.focused) {
+      signal(cm, "focus", cm);
+      cm.state.focused = true;
+      addClass(cm.display.wrapper, "CodeMirror-focused");
+      // This test prevents this from firing when a context
+      // menu is closed (since the input reset would kill the
+      // select-all detection hack)
+      if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
+        cm.display.input.reset();
+        if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
+      }
+      cm.display.input.receivedFocus();
+    }
+    restartBlink(cm);
+  }
+  function onBlur(cm) {
+    if (cm.state.delayingBlurEvent) return;
+
+    if (cm.state.focused) {
+      signal(cm, "blur", cm);
+      cm.state.focused = false;
+      rmClass(cm.display.wrapper, "CodeMirror-focused");
+    }
+    clearInterval(cm.display.blinker);
+    setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
+  }
+
+  // CONTEXT MENU HANDLING
+
+  // To make the context menu work, we need to briefly unhide the
+  // textarea (making it as unobtrusive as possible) to let the
+  // right-click take effect on it.
+  function onContextMenu(cm, e) {
+    if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
+    cm.display.input.onContextMenu(e);
+  }
+
+  function contextMenuInGutter(cm, e) {
+    if (!hasHandler(cm, "gutterContextMenu")) return false;
+    return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+  }
+
+  // UPDATING
+
+  // Compute the position of the end of a change (its 'to' property
+  // refers to the pre-change end).
+  var changeEnd = CodeMirror.changeEnd = function(change) {
+    if (!change.text) return change.to;
+    return Pos(change.from.line + change.text.length - 1,
+               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
+  };
+
+  // Adjust a position to refer to the post-change position of the
+  // same text, or the end of the change if the change covers it.
+  function adjustForChange(pos, change) {
+    if (cmp(pos, change.from) < 0) return pos;
+    if (cmp(pos, change.to) <= 0) return changeEnd(change);
+
+    var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
+    if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
+    return Pos(line, ch);
+  }
+
+  function computeSelAfterChange(doc, change) {
+    var out = [];
+    for (var i = 0; i < doc.sel.ranges.length; i++) {
+      var range = doc.sel.ranges[i];
+      out.push(new Range(adjustForChange(range.anchor, change),
+                         adjustForChange(range.head, change)));
+    }
+    return normalizeSelection(out, doc.sel.primIndex);
+  }
+
+  function offsetPos(pos, old, nw) {
+    if (pos.line == old.line)
+      return Pos(nw.line, pos.ch - old.ch + nw.ch);
+    else
+      return Pos(nw.line + (pos.line - old.line), pos.ch);
+  }
+
+  // Used by replaceSelections to allow moving the selection to the
+  // start or around the replaced test. Hint may be "start" or "around".
+  function computeReplacedSel(doc, changes, hint) {
+    var out = [];
+    var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
+    for (var i = 0; i < changes.length; i++) {
+      var change = changes[i];
+      var from = offsetPos(change.from, oldPrev, newPrev);
+      var to = offsetPos(changeEnd(change), oldPrev, newPrev);
+      oldPrev = change.to;
+      newPrev = to;
+      if (hint == "around") {
+        var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
+        out[i] = new Range(inv ? to : from, inv ? from : to);
+      } else {
+        out[i] = new Range(from, from);
+      }
+    }
+    return new Selection(out, doc.sel.primIndex);
+  }
+
+  // Allow "beforeChange" event handlers to influence a change
+  function filterChange(doc, change, update) {
+    var obj = {
+      canceled: false,
+      from: change.from,
+      to: change.to,
+      text: change.text,
+      origin: change.origin,
+      cancel: function() { this.canceled = true; }
+    };
+    if (update) obj.update = function(from, to, text, origin) {
+      if (from) this.from = clipPos(doc, from);
+      if (to) this.to = clipPos(doc, to);
+      if (text) this.text = text;
+      if (origin !== undefined) this.origin = origin;
+    };
+    signal(doc, "beforeChange", doc, obj);
+    if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
+
+    if (obj.canceled) return null;
+    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
+  }
+
+  // Apply a change to a document, and add it to the document's
+  // history, and propagating it to all linked documents.
+  function makeChange(doc, change, ignoreReadOnly) {
+    if (doc.cm) {
+      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
+      if (doc.cm.state.suppressEdits) return;
+    }
+
+    if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
+      change = filterChange(doc, change, true);
+      if (!change) return;
+    }
+
+    // Possibly split or suppress the update based on the presence
+    // of read-only spans in its range.
+    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
+    if (split) {
+      for (var i = split.length - 1; i >= 0; --i)
+        makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
+    } else {
+      makeChangeInner(doc, change);
+    }
+  }
+
+  function makeChangeInner(doc, change) {
+    if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
+    var selAfter = computeSelAfterChange(doc, change);
+    addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
+
+    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
+    var rebased = [];
+
+    linkedDocs(doc, function(doc, sharedHist) {
+      if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+        rebaseHist(doc.history, change);
+        rebased.push(doc.history);
+      }
+      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
+    });
+  }
+
+  // Revert a change stored in a document's history.
+  function makeChangeFromHistory(doc, type, allowSelectionOnly) {
+    if (doc.cm && doc.cm.state.suppressEdits) return;
+
+    var hist = doc.history, event, selAfter = doc.sel;
+    var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
+
+    // Verify that there is a useable event (so that ctrl-z won't
+    // needlessly clear selection events)
+    for (var i = 0; i < source.length; i++) {
+      event = source[i];
+      if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
+        break;
+    }
+    if (i == source.length) return;
+    hist.lastOrigin = hist.lastSelOrigin = null;
+
+    for (;;) {
+      event = source.pop();
+      if (event.ranges) {
+        pushSelectionToHistory(event, dest);
+        if (allowSelectionOnly && !event.equals(doc.sel)) {
+          setSelection(doc, event, {clearRedo: false});
+          return;
+        }
+        selAfter = event;
+      }
+      else break;
+    }
+
+    // Build up a reverse change object to add to the opposite history
+    // stack (redo when undoing, and vice versa).
+    var antiChanges = [];
+    pushSelectionToHistory(selAfter, dest);
+    dest.push({changes: antiChanges, generation: hist.generation});
+    hist.generation = event.generation || ++hist.maxGeneration;
+
+    var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
+
+    for (var i = event.changes.length - 1; i >= 0; --i) {
+      var change = event.changes[i];
+      change.origin = type;
+      if (filter && !filterChange(doc, change, false)) {
+        source.length = 0;
+        return;
+      }
+
+      antiChanges.push(historyChangeFromChange(doc, change));
+
+      var after = i ? computeSelAfterChange(doc, change) : lst(source);
+      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
+      if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
+      var rebased = [];
+
+      // Propagate to the linked documents
+      linkedDocs(doc, function(doc, sharedHist) {
+        if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+          rebaseHist(doc.history, change);
+          rebased.push(doc.history);
+        }
+        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
+      });
+    }
+  }
+
+  // Sub-views need their line numbers shifted when text is added
+  // above or below them in the parent document.
+  function shiftDoc(doc, distance) {
+    if (distance == 0) return;
+    doc.first += distance;
+    doc.sel = new Selection(map(doc.sel.ranges, function(range) {
+      return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
+                       Pos(range.head.line + distance, range.head.ch));
+    }), doc.sel.primIndex);
+    if (doc.cm) {
+      regChange(doc.cm, doc.first, doc.first - distance, distance);
+      for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
+        regLineChange(doc.cm, l, "gutter");
+    }
+  }
+
+  // More lower-level change function, handling only a single document
+  // (not linked ones).
+  function makeChangeSingleDoc(doc, change, selAfter, spans) {
+    if (doc.cm && !doc.cm.curOp)
+      return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
+
+    if (change.to.line < doc.first) {
+      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
+      return;
+    }
+    if (change.from.line > doc.lastLine()) return;
+
+    // Clip the change to the size of this doc
+    if (change.from.line < doc.first) {
+      var shift = change.text.length - 1 - (doc.first - change.from.line);
+      shiftDoc(doc, shift);
+      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
+                text: [lst(change.text)], origin: change.origin};
+    }
+    var last = doc.lastLine();
+    if (change.to.line > last) {
+      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
+                text: [change.text[0]], origin: change.origin};
+    }
+
+    change.removed = getBetween(doc, change.from, change.to);
+
+    if (!selAfter) selAfter = computeSelAfterChange(doc, change);
+    if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
+    else updateDoc(doc, change, spans);
+    setSelectionNoUndo(doc, selAfter, sel_dontScroll);
+  }
+
+  // Handle the interaction of a change to a document with the editor
+  // that this document is part of.
+  function makeChangeSingleDocInEditor(cm, change, spans) {
+    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
+
+    var recomputeMaxLength = false, checkWidthStart = from.line;
+    if (!cm.options.lineWrapping) {
+      checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
+      doc.iter(checkWidthStart, to.line + 1, function(line) {
+        if (line == display.maxLine) {
+          recomputeMaxLength = true;
+          return true;
+        }
+      });
+    }
+
+    if (doc.sel.contains(change.from, change.to) > -1)
+      signalCursorActivity(cm);
+
+    updateDoc(doc, change, spans, estimateHeight(cm));
+
+    if (!cm.options.lineWrapping) {
+      doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
+        var len = lineLength(line);
+        if (len > display.maxLineLength) {
+          display.maxLine = line;
+          display.maxLineLength = len;
+          display.maxLineChanged = true;
+          recomputeMaxLength = false;
+        }
+      });
+      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
+    }
+
+    // Adjust frontier, schedule worker
+    doc.frontier = Math.min(doc.frontier, from.line);
+    startWorker(cm, 400);
+
+    var lendiff = change.text.length - (to.line - from.line) - 1;
+    // Remember that these lines changed, for updating the display
+    if (change.full)
+      regChange(cm);
+    else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
+      regLineChange(cm, from.line, "text");
+    else
+      regChange(cm, from.line, to.line + 1, lendiff);
+
+    var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
+    if (changeHandler || changesHandler) {
+      var obj = {
+        from: from, to: to,
+        text: change.text,
+        removed: change.removed,
+        origin: change.origin
+      };
+      if (changeHandler) signalLater(cm, "change", cm, obj);
+      if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
+    }
+    cm.display.selForContextMenu = null;
+  }
+
+  function replaceRange(doc, code, from, to, origin) {
+    if (!to) to = from;
+    if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
+    if (typeof code == "string") code = splitLines(code);
+    makeChange(doc, {from: from, to: to, text: code, origin: origin});
+  }
+
+  // SCROLLING THINGS INTO VIEW
+
+  // If an editor sits on the top or bottom of the window, partially
+  // scrolled out of view, this ensures that the cursor is visible.
+  function maybeScrollWindow(cm, coords) {
+    if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
+
+    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
+    if (coords.top + box.top < 0) doScroll = true;
+    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
+    if (doScroll != null && !phantom) {
+      var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
+                           (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
+                           (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
+                           coords.left + "px; width: 2px;");
+      cm.display.lineSpace.appendChild(scrollNode);
+      scrollNode.scrollIntoView(doScroll);
+      cm.display.lineSpace.removeChild(scrollNode);
+    }
+  }
+
+  // Scroll a given position into view (immediately), verifying that
+  // it actually became visible (as line heights are accurately
+  // measured, the position of something may 'drift' during drawing).
+  function scrollPosIntoView(cm, pos, end, margin) {
+    if (margin == null) margin = 0;
+    for (var limit = 0; limit < 5; limit++) {
+      var changed = false, coords = cursorCoords(cm, pos);
+      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
+      var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
+                                         Math.min(coords.top, endCoords.top) - margin,
+                                         Math.max(coords.left, endCoords.left),
+                                         Math.max(coords.bottom, endCoords.bottom) + margin);
+      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
+      if (scrollPos.scrollTop != null) {
+        setScrollTop(cm, scrollPos.scrollTop);
+        if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
+      }
+      if (scrollPos.scrollLeft != null) {
+        setScrollLeft(cm, scrollPos.scrollLeft);
+        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
+      }
+      if (!changed) break;
+    }
+    return coords;
+  }
+
+  // Scroll a given set of coordinates into view (immediately).
+  function scrollIntoView(cm, x1, y1, x2, y2) {
+    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
+    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
+    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
+  }
+
+  // Calculate a new scroll position needed to scroll the given
+  // rectangle into view. Returns an object with scrollTop and
+  // scrollLeft properties. When these are undefined, the
+  // vertical/horizontal position does not need to be adjusted.
+  function calculateScrollPos(cm, x1, y1, x2, y2) {
+    var display = cm.display, snapMargin = textHeight(cm.display);
+    if (y1 < 0) y1 = 0;
+    var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
+    var screen = displayHeight(cm), result = {};
+    if (y2 - y1 > screen) y2 = y1 + screen;
+    var docBottom = cm.doc.height + paddingVert(display);
+    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
+    if (y1 < screentop) {
+      result.scrollTop = atTop ? 0 : y1;
+    } else if (y2 > screentop + screen) {
+      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
+      if (newTop != screentop) result.scrollTop = newTop;
+    }
+
+    var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
+    var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
+    var tooWide = x2 - x1 > screenw;
+    if (tooWide) x2 = x1 + screenw;
+    if (x1 < 10)
+      result.scrollLeft = 0;
+    else if (x1 < screenleft)
+      result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
+    else if (x2 > screenw + screenleft - 3)
+      result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
+    return result;
+  }
+
+  // Store a relative adjustment to the scroll position in the current
+  // operation (to be applied when the operation finishes).
+  function addToScrollPos(cm, left, top) {
+    if (left != null || top != null) resolveScrollToPos(cm);
+    if (left != null)
+      cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
+    if (top != null)
+      cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
+  }
+
+  // Make sure that at the end of the operation the current cursor is
+  // shown.
+  function ensureCursorVisible(cm) {
+    resolveScrollToPos(cm);
+    var cur = cm.getCursor(), from = cur, to = cur;
+    if (!cm.options.lineWrapping) {
+      from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
+      to = Pos(cur.line, cur.ch + 1);
+    }
+    cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
+  }
+
+  // When an operation has its scrollToPos property set, and another
+  // scroll action is applied before the end of the operation, this
+  // 'simulates' scrolling that position into view in a cheap way, so
+  // that the effect of intermediate scroll commands is not ignored.
+  function resolveScrollToPos(cm) {
+    var range = cm.curOp.scrollToPos;
+    if (range) {
+      cm.curOp.scrollToPos = null;
+      var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
+      var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
+                                    Math.min(from.top, to.top) - range.margin,
+                                    Math.max(from.right, to.right),
+                                    Math.max(from.bottom, to.bottom) + range.margin);
+      cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+    }
+  }
+
+  // API UTILITIES
+
+  // Indent the given line. The how parameter can be "smart",
+  // "add"/null, "subtract", or "prev". When aggressive is false
+  // (typically set to true for forced single-line indents), empty
+  // lines are not indented, and places where the mode returns Pass
+  // are left alone.
+  function indentLine(cm, n, how, aggressive) {
+    var doc = cm.doc, state;
+    if (how == null) how = "add";
+    if (how == "smart") {
+      // Fall back to "prev" when the mode doesn't have an indentation
+      // method.
+      if (!doc.mode.indent) how = "prev";
+      else state = getStateBefore(cm, n);
+    }
+
+    var tabSize = cm.options.tabSize;
+    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
+    if (line.stateAfter) line.stateAfter = null;
+    var curSpaceString = line.text.match(/^\s*/)[0], indentation;
+    if (!aggressive && !/\S/.test(line.text)) {
+      indentation = 0;
+      how = "not";
+    } else if (how == "smart") {
+      indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+      if (indentation == Pass || indentation > 150) {
+        if (!aggressive) return;
+        how = "prev";
+      }
+    }
+    if (how == "prev") {
+      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
+      else indentation = 0;
+    } else if (how == "add") {
+      indentation = curSpace + cm.options.indentUnit;
+    } else if (how == "subtract") {
+      indentation = curSpace - cm.options.indentUnit;
+    } else if (typeof how == "number") {
+      indentation = curSpace + how;
+    }
+    indentation = Math.max(0, indentation);
+
+    var indentString = "", pos = 0;
+    if (cm.options.indentWithTabs)
+      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
+    if (pos < indentation) indentString += spaceStr(indentation - pos);
+
+    if (indentString != curSpaceString) {
+      replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+      line.stateAfter = null;
+      return true;
+    } else {
+      // Ensure that, if the cursor was in the whitespace at the start
+      // of the line, it is moved to the end of that space.
+      for (var i = 0; i < doc.sel.ranges.length; i++) {
+        var range = doc.sel.ranges[i];
+        if (range.head.line == n && range.head.ch < curSpaceString.length) {
+          var pos = Pos(n, curSpaceString.length);
+          replaceOneSelection(doc, i, new Range(pos, pos));
+          break;
+        }
+      }
+    }
+  }
+
+  // Utility for applying a change to a line by handle or number,
+  // returning the number and optionally registering the line as
+  // changed.
+  function changeLine(doc, handle, changeType, op) {
+    var no = handle, line = handle;
+    if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
+    else no = lineNo(handle);
+    if (no == null) return null;
+    if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
+    return line;
+  }
+
+  // Helper for deleting text near the selection(s), used to implement
+  // backspace, delete, and similar functionality.
+  function deleteNearSelection(cm, compute) {
+    var ranges = cm.doc.sel.ranges, kill = [];
+    // Build up a set of ranges to kill first, merging overlapping
+    // ranges.
+    for (var i = 0; i < ranges.length; i++) {
+      var toKill = compute(ranges[i]);
+      while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
+        var replaced = kill.pop();
+        if (cmp(replaced.from, toKill.from) < 0) {
+          toKill.from = replaced.from;
+          break;
+        }
+      }
+      kill.push(toKill);
+    }
+    // Next, remove those actual ranges.
+    runInOp(cm, function() {
+      for (var i = kill.length - 1; i >= 0; i--)
+        replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
+      ensureCursorVisible(cm);
+    });
+  }
+
+  // Used for horizontal relative motion. Dir is -1 or 1 (left or
+  // right), unit can be "char", "column" (like char, but doesn't
+  // cross line boundaries), "word" (across next word), or "group" (to
+  // the start of next group of word or non-word-non-whitespace
+  // chars). The visually param controls whether, in right-to-left
+  // text, direction 1 means to move towards the next index in the
+  // string, or towards the character to the right of the current
+  // position. The resulting position will have a hitSide=true
+  // property if it reached the end of the document.
+  function findPosH(doc, pos, dir, unit, visually) {
+    var line = pos.line, ch = pos.ch, origDir = dir;
+    var lineObj = getLine(doc, line);
+    var possible = true;
+    function findNextLine() {
+      var l = line + dir;
+      if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
+      line = l;
+      return lineObj = getLine(doc, l);
+    }
+    function moveOnce(boundToLine) {
+      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
+      if (next == null) {
+        if (!boundToLine && findNextLine()) {
+          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
+          else ch = dir < 0 ? lineObj.text.length : 0;
+        } else return (possible = false);
+      } else ch = next;
+      return true;
+    }
+
+    if (unit == "char") moveOnce();
+    else if (unit == "column") moveOnce(true);
+    else if (unit == "word" || unit == "group") {
+      var sawType = null, group = unit == "group";
+      var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
+      for (var first = true;; first = false) {
+        if (dir < 0 && !moveOnce(!first)) break;
+        var cur = lineObj.text.charAt(ch) || "\n";
+        var type = isWordChar(cur, helper) ? "w"
+          : group && cur == "\n" ? "n"
+          : !group || /\s/.test(cur) ? null
+          : "p";
+        if (group && !first && !type) type = "s";
+        if (sawType && sawType != type) {
+          if (dir < 0) {dir = 1; moveOnce();}
+          break;
+        }
+
+        if (type) sawType = type;
+        if (dir > 0 && !moveOnce(!first)) break;
+      }
+    }
+    var result = skipAtomic(doc, Pos(line, ch), origDir, true);
+    if (!possible) result.hitSide = true;
+    return result;
+  }
+
+  // For relative vertical movement. Dir may be -1 or 1. Unit can be
+  // "page" or "line". The resulting position will have a hitSide=true
+  // property if it reached the end of the document.
+  function findPosV(cm, pos, dir, unit) {
+    var doc = cm.doc, x = pos.left, y;
+    if (unit == "page") {
+      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+      y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
+    } else if (unit == "line") {
+      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
+    }
+    for (;;) {
+      var target = coordsChar(cm, x, y);
+      if (!target.outside) break;
+      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
+      y += dir * 5;
+    }
+    return target;
+  }
+
+  // EDITOR METHODS
+
+  // The publicly visible API. Note that methodOp(f) means
+  // 'wrap f in an operation, performed on its `this` parameter'.
+
+  // This is not the complete set of editor methods. Most of the
+  // methods defined on the Doc type are also injected into
+  // CodeMirror.prototype, for backwards compatibility and
+  // convenience.
+
+  CodeMirror.prototype = {
+    constructor: CodeMirror,
+    focus: function(){window.focus(); this.display.input.focus();},
+
+    setOption: function(option, value) {
+      var options = this.options, old = options[option];
+      if (options[option] == value && option != "mode") return;
+      options[option] = value;
+      if (optionHandlers.hasOwnProperty(option))
+        operation(this, optionHandlers[option])(this, value, old);
+    },
+
+    getOption: function(option) {return this.options[option];},
+    getDoc: function() {return this.doc;},
+
+    addKeyMap: function(map, bottom) {
+      this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
+    },
+    removeKeyMap: function(map) {
+      var maps = this.state.keyMaps;
+      for (var i = 0; i < maps.length; ++i)
+        if (maps[i] == map || maps[i].name == map) {
+          maps.splice(i, 1);
+          return true;
+        }
+    },
+
+    addOverlay: methodOp(function(spec, options) {
+      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
+      if (mode.startState) throw new Error("Overlays may not be stateful.");
+      this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
+      this.state.modeGen++;
+      regChange(this);
+    }),
+    removeOverlay: methodOp(function(spec) {
+      var overlays = this.state.overlays;
+      for (var i = 0; i < overlays.length; ++i) {
+        var cur = overlays[i].modeSpec;
+        if (cur == spec || typeof spec == "string" && cur.name == spec) {
+          overlays.splice(i, 1);
+          this.state.modeGen++;
+          regChange(this);
+          return;
+        }
+      }
+    }),
+
+    indentLine: methodOp(function(n, dir, aggressive) {
+      if (typeof dir != "string" && typeof dir != "number") {
+        if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
+        else dir = dir ? "add" : "subtract";
+      }
+      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
+    }),
+    indentSelection: methodOp(function(how) {
+      var ranges = this.doc.sel.ranges, end = -1;
+      for (var i = 0; i < ranges.length; i++) {
+        var range = ranges[i];
+        if (!range.empty()) {
+          var from = range.from(), to = range.to();
+          var start = Math.max(end, from.line);
+          end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
+          for (var j = start; j < end; ++j)
+            indentLine(this, j, how);
+          var newRanges = this.doc.sel.ranges;
+          if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
+            replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
+        } else if (range.head.line > end) {
+          indentLine(this, range.head.line, how, true);
+          end = range.head.line;
+          if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
+        }
+      }
+    }),
+
+    // Fetch the parser token for a given character. Useful for hacks
+    // that want to inspect the mode state (say, for completion).
+    getTokenAt: function(pos, precise) {
+      return takeToken(this, pos, precise);
+    },
+
+    getLineTokens: function(line, precise) {
+      return takeToken(this, Pos(line), precise, true);
+    },
+
+    getTokenTypeAt: function(pos) {
+      pos = clipPos(this.doc, pos);
+      var styles = getLineStyles(this, getLine(this.doc, pos.line));
+      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
+      var type;
+      if (ch == 0) type = styles[2];
+      else for (;;) {
+        var mid = (before + after) >> 1;
+        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
+        else if (styles[mid * 2 + 1] < ch) before = mid + 1;
+        else { type = styles[mid * 2 + 2]; break; }
+      }
+      var cut = type ? type.indexOf("cm-overlay ") : -1;
+      return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
+    },
+
+    getModeAt: function(pos) {
+      var mode = this.doc.mode;
+      if (!mode.innerMode) return mode;
+      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
+    },
+
+    getHelper: function(pos, type) {
+      return this.getHelpers(pos, type)[0];
+    },
+
+    getHelpers: function(pos, type) {
+      var found = [];
+      if (!helpers.hasOwnProperty(type)) return found;
+      var help = helpers[type], mode = this.getModeAt(pos);
+      if (typeof mode[type] == "string") {
+        if (help[mode[type]]) found.push(help[mode[type]]);
+      } else if (mode[type]) {
+        for (var i = 0; i < mode[type].length; i++) {
+          var val = help[mode[type][i]];
+          if (val) found.push(val);
+        }
+      } else if (mode.helperType && help[mode.helperType]) {
+        found.push(help[mode.helperType]);
+      } else if (help[mode.name]) {
+        found.push(help[mode.name]);
+      }
+      for (var i = 0; i < help._global.length; i++) {
+        var cur = help._global[i];
+        if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+          found.push(cur.val);
+      }
+      return found;
+    },
+
+    getStateAfter: function(line, precise) {
+      var doc = this.doc;
+      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
+      return getStateBefore(this, line + 1, precise);
+    },
+
+    cursorCoords: function(start, mode) {
+      var pos, range = this.doc.sel.primary();
+      if (start == null) pos = range.head;
+      else if (typeof start == "object") pos = clipPos(this.doc, start);
+      else pos = start ? range.from() : range.to();
+      return cursorCoords(this, pos, mode || "page");
+    },
+
+    charCoords: function(pos, mode) {
+      return charCoords(this, clipPos(this.doc, pos), mode || "page");
+    },
+
+    coordsChar: function(coords, mode) {
+      coords = fromCoordSystem(this, coords, mode || "page");
+      return coordsChar(this, coords.left, coords.top);
+    },
+
+    lineAtHeight: function(height, mode) {
+      height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
+      return lineAtHeight(this.doc, height + this.display.viewOffset);
+    },
+    heightAtLine: function(line, mode) {
+      var end = false, lineObj;
+      if (typeof line == "number") {
+        var last = this.doc.first + this.doc.size - 1;
+        if (line < this.doc.first) line = this.doc.first;
+        else if (line > last) { line = last; end = true; }
+        lineObj = getLine(this.doc, line);
+      } else {
+        lineObj = line;
+      }
+      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
+        (end ? this.doc.height - heightAtLine(lineObj) : 0);
+    },
+
+    defaultTextHeight: function() { return textHeight(this.display); },
+    defaultCharWidth: function() { return charWidth(this.display); },
+
+    setGutterMarker: methodOp(function(line, gutterID, value) {
+      return changeLine(this.doc, line, "gutter", function(line) {
+        var markers = line.gutterMarkers || (line.gutterMarkers = {});
+        markers[gutterID] = value;
+        if (!value && isEmpty(markers)) line.gutterMarkers = null;
+        return true;
+      });
+    }),
+
+    clearGutter: methodOp(function(gutterID) {
+      var cm = this, doc = cm.doc, i = doc.first;
+      doc.iter(function(line) {
+        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
+          line.gutterMarkers[gutterID] = null;
+          regLineChange(cm, i, "gutter");
+          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
+        }
+        ++i;
+      });
+    }),
+
+    lineInfo: function(line) {
+      if (typeof line == "number") {
+        if (!isLine(this.doc, line)) return null;
+        var n = line;
+        line = getLine(this.doc, line);
+        if (!line) return null;
+      } else {
+        var n = lineNo(line);
+        if (n == null) return null;
+      }
+      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
+              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
+              widgets: line.widgets};
+    },
+
+    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
+
+    addWidget: function(pos, node, scroll, vert, horiz) {
+      var display = this.display;
+      pos = cursorCoords(this, clipPos(this.doc, pos));
+      var top = pos.bottom, left = pos.left;
+      node.style.position = "absolute";
+      node.setAttribute("cm-ignore-events", "true");
+      this.display.input.setUneditable(node);
+      display.sizer.appendChild(node);
+      if (vert == "over") {
+        top = pos.top;
+      } else if (vert == "above" || vert == "near") {
+        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
+        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
+        // Default to positioning above (if specified and possible); otherwise default to positioning below
+        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
+          top = pos.top - node.offsetHeight;
+        else if (pos.bottom + node.offsetHeight <= vspace)
+          top = pos.bottom;
+        if (left + node.offsetWidth > hspace)
+          left = hspace - node.offsetWidth;
+      }
+      node.style.top = top + "px";
+      node.style.left = node.style.right = "";
+      if (horiz == "right") {
+        left = display.sizer.clientWidth - node.offsetWidth;
+        node.style.right = "0px";
+      } else {
+        if (horiz == "left") left = 0;
+        else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
+        node.style.left = left + "px";
+      }
+      if (scroll)
+        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
+    },
+
+    triggerOnKeyDown: methodOp(onKeyDown),
+    triggerOnKeyPress: methodOp(onKeyPress),
+    triggerOnKeyUp: onKeyUp,
+
+    execCommand: function(cmd) {
+      if (commands.hasOwnProperty(cmd))
+        return commands[cmd](this);
+    },
+
+    triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
+
+    findPosH: function(from, amount, unit, visually) {
+      var dir = 1;
+      if (amount < 0) { dir = -1; amount = -amount; }
+      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+        cur = findPosH(this.doc, cur, dir, unit, visually);
+        if (cur.hitSide) break;
+      }
+      return cur;
+    },
+
+    moveH: methodOp(function(dir, unit) {
+      var cm = this;
+      cm.extendSelectionsBy(function(range) {
+        if (cm.display.shift || cm.doc.extend || range.empty())
+          return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
+        else
+          return dir < 0 ? range.from() : range.to();
+      }, sel_move);
+    }),
+
+    deleteH: methodOp(function(dir, unit) {
+      var sel = this.doc.sel, doc = this.doc;
+      if (sel.somethingSelected())
+        doc.replaceSelection("", null, "+delete");
+      else
+        deleteNearSelection(this, function(range) {
+          var other = findPosH(doc, range.head, dir, unit, false);
+          return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
+        });
+    }),
+
+    findPosV: function(from, amount, unit, goalColumn) {
+      var dir = 1, x = goalColumn;
+      if (amount < 0) { dir = -1; amount = -amount; }
+      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+        var coords = cursorCoords(this, cur, "div");
+        if (x == null) x = coords.left;
+        else coords.left = x;
+        cur = findPosV(this, coords, dir, unit);
+        if (cur.hitSide) break;
+      }
+      return cur;
+    },
+
+    moveV: methodOp(function(dir, unit) {
+      var cm = this, doc = this.doc, goals = [];
+      var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
+      doc.extendSelectionsBy(function(range) {
+        if (collapse)
+          return dir < 0 ? range.from() : range.to();
+        var headPos = cursorCoords(cm, range.head, "div");
+        if (range.goalColumn != null) headPos.left = range.goalColumn;
+        goals.push(headPos.left);
+        var pos = findPosV(cm, headPos, dir, unit);
+        if (unit == "page" && range == doc.sel.primary())
+          addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
+        return pos;
+      }, sel_move);
+      if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
+        doc.sel.ranges[i].goalColumn = goals[i];
+    }),
+
+    // Find the word at the given position (as returned by coordsChar).
+    findWordAt: function(pos) {
+      var doc = this.doc, line = getLine(doc, pos.line).text;
+      var start = pos.ch, end = pos.ch;
+      if (line) {
+        var helper = this.getHelper(pos, "wordChars");
+        if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
+        var startChar = line.charAt(start);
+        var check = isWordChar(startChar, helper)
+          ? function(ch) { return isWordChar(ch, helper); }
+          : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
+          : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
+        while (start > 0 && check(line.charAt(start - 1))) --start;
+        while (end < line.length && check(line.charAt(end))) ++end;
+      }
+      return new Range(Pos(pos.line, start), Pos(pos.line, end));
+    },
+
+    toggleOverwrite: function(value) {
+      if (value != null && value == this.state.overwrite) return;
+      if (this.state.overwrite = !this.state.overwrite)
+        addClass(this.display.cursorDiv, "CodeMirror-overwrite");
+      else
+        rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
+
+      signal(this, "overwriteToggle", this, this.state.overwrite);
+    },
+    hasFocus: function() { return this.display.input.getField() == activeElt(); },
+
+    scrollTo: methodOp(function(x, y) {
+      if (x != null || y != null) resolveScrollToPos(this);
+      if (x != null) this.curOp.scrollLeft = x;
+      if (y != null) this.curOp.scrollTop = y;
+    }),
+    getScrollInfo: function() {
+      var scroller = this.display.scroller;
+      return {left: scroller.scrollLeft, top: scroller.scrollTop,
+              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
+              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
+              clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
+    },
+
+    scrollIntoView: methodOp(function(range, margin) {
+      if (range == null) {
+        range = {from: this.doc.sel.primary().head, to: null};
+        if (margin == null) margin = this.options.cursorScrollMargin;
+      } else if (typeof range == "number") {
+        range = {from: Pos(range, 0), to: null};
+      } else if (range.from == null) {
+        range = {from: range, to: null};
+      }
+      if (!range.to) range.to = range.from;
+      range.margin = margin || 0;
+
+      if (range.from.line != null) {
+        resolveScrollToPos(this);
+        this.curOp.scrollToPos = range;
+      } else {
+        var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
+                                      Math.min(range.from.top, range.to.top) - range.margin,
+                                      Math.max(range.from.right, range.to.right),
+                                      Math.max(range.from.bottom, range.to.bottom) + range.margin);
+        this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+      }
+    }),
+
+    setSize: methodOp(function(width, height) {
+      var cm = this;
+      function interpret(val) {
+        return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
+      }
+      if (width != null) cm.display.wrapper.style.width = interpret(width);
+      if (height != null) cm.display.wrapper.style.height = interpret(height);
+      if (cm.options.lineWrapping) clearLineMeasurementCache(this);
+      var lineNo = cm.display.viewFrom;
+      cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
+        if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
+          if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
+        ++lineNo;
+      });
+      cm.curOp.forceUpdate = true;
+      signal(cm, "refresh", this);
+    }),
+
+    operation: function(f){return runInOp(this, f);},
+
+    refresh: methodOp(function() {
+      var oldHeight = this.display.cachedTextHeight;
+      regChange(this);
+      this.curOp.forceUpdate = true;
+      clearCaches(this);
+      this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
+      updateGutterSpace(this);
+      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
+        estimateLineHeights(this);
+      signal(this, "refresh", this);
+    }),
+
+    swapDoc: methodOp(function(doc) {
+      var old = this.doc;
+      old.cm = null;
+      attachDoc(this, doc);
+      clearCaches(this);
+      this.display.input.reset();
+      this.scrollTo(doc.scrollLeft, doc.scrollTop);
+      this.curOp.forceScroll = true;
+      signalLater(this, "swapDoc", this, old);
+      return old;
+    }),
+
+    getInputField: function(){return this.display.input.getField();},
+    getWrapperElement: function(){return this.display.wrapper;},
+    getScrollerElement: function(){return this.display.scroller;},
+    getGutterElement: function(){return this.display.gutters;}
+  };
+  eventMixin(CodeMirror);
+
+  // OPTION DEFAULTS
+
+  // The default configuration options.
+  var defaults = CodeMirror.defaults = {};
+  // Functions to run when options are changed.
+  var optionHandlers = CodeMirror.optionHandlers = {};
+
+  function option(name, deflt, handle, notOnInit) {
+    CodeMirror.defaults[name] = deflt;
+    if (handle) optionHandlers[name] =
+      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
+  }
+
+  // Passed to option handlers when there is no old value.
+  var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
+
+  // These two are, on init, called from the constructor because they
+  // have to be initialized before the editor can start at all.
+  option("value", "", function(cm, val) {
+    cm.setValue(val);
+  }, true);
+  option("mode", null, function(cm, val) {
+    cm.doc.modeOption = val;
+    loadMode(cm);
+  }, true);
+
+  option("indentUnit", 2, loadMode, true);
+  option("indentWithTabs", false);
+  option("smartIndent", true);
+  option("tabSize", 4, function(cm) {
+    resetModeState(cm);
+    clearCaches(cm);
+    regChange(cm);
+  }, true);
+  option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
+    cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+    if (old != CodeMirror.Init) cm.refresh();
+  });
+  option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
+  option("electricChars", true);
+  option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
+    throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
+  }, true);
+  option("rtlMoveVisually", !windows);
+  option("wholeLineUpdateBefore", true);
+
+  option("theme", "default", function(cm) {
+    themeChanged(cm);
+    guttersChanged(cm);
+  }, true);
+  option("keyMap", "default", function(cm, val, old) {
+    var next = getKeyMap(val);
+    var prev = old != CodeMirror.Init && getKeyMap(old);
+    if (prev && prev.detach) prev.detach(cm, next);
+    if (next.attach) next.attach(cm, prev || null);
+  });
+  option("extraKeys", null);
+
+  option("lineWrapping", false, wrappingChanged, true);
+  option("gutters", [], function(cm) {
+    setGuttersForLineNumbers(cm.options);
+    guttersChanged(cm);
+  }, true);
+  option("fixedGutter", true, function(cm, val) {
+    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
+    cm.refresh();
+  }, true);
+  option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
+  option("scrollbarStyle", "native", function(cm) {
+    initScrollbars(cm);
+    updateScrollbars(cm);
+    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
+    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
+  }, true);
+  option("lineNumbers", false, function(cm) {
+    setGuttersForLineNumbers(cm.options);
+    guttersChanged(cm);
+  }, true);
+  option("firstLineNumber", 1, guttersChanged, true);
+  option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
+  option("showCursorWhenSelecting", false, updateSelection, true);
+
+  option("resetSelectionOnContextMenu", true);
+  option("lineWiseCopyCut", true);
+
+  option("readOnly", false, function(cm, val) {
+    if (val == "nocursor") {
+      onBlur(cm);
+      cm.display.input.blur();
+      cm.display.disabled = true;
+    } else {
+      cm.display.disabled = false;
+      if (!val) cm.display.input.reset();
+    }
+  });
+  option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
+  option("dragDrop", true, dragDropChanged);
+
+  option("cursorBlinkRate", 530);
+  option("cursorScrollMargin", 0);
+  option("cursorHeight", 1, updateSelection, true);
+  option("singleCursorHeightPerLine", true, updateSelection, true);
+  option("workTime", 100);
+  option("workDelay", 100);
+  option("flattenSpans", true, resetModeState, true);
+  option("addModeClass", false, resetModeState, true);
+  option("pollInterval", 100);
+  option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
+  option("historyEventDelay", 1250);
+  option("viewportMargin", 10, function(cm){cm.refresh();}, true);
+  option("maxHighlightLength", 10000, resetModeState, true);
+  option("moveInputWithCursor", true, function(cm, val) {
+    if (!val) cm.display.input.resetPosition();
+  });
+
+  option("tabindex", null, function(cm, val) {
+    cm.display.input.getField().tabIndex = val || "";
+  });
+  option("autofocus", null);
+
+  // MODE DEFINITION AND QUERYING
+
+  // Known modes, by name and by MIME
+  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
+
+  // Extra arguments are stored as the mode's dependencies, which is
+  // used by (legacy) mechanisms like loadmode.js to automatically
+  // load a mode. (Preferred mechanism is the require/define calls.)
+  CodeMirror.defineMode = function(name, mode) {
+    if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
+    if (arguments.length > 2)
+      mode.dependencies = Array.prototype.slice.call(arguments, 2);
+    modes[name] = mode;
+  };
+
+  CodeMirror.defineMIME = function(mime, spec) {
+    mimeModes[mime] = spec;
+  };
+
+  // Given a MIME type, a {name, ...options} config object, or a name
+  // string, return a mode config object.
+  CodeMirror.resolveMode = function(spec) {
+    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+      spec = mimeModes[spec];
+    } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+      var found = mimeModes[spec.name];
+      if (typeof found == "string") found = {name: found};
+      spec = createObj(found, spec);
+      spec.name = found.name;
+    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+      return CodeMirror.resolveMode("application/xml");
+    }
+    if (typeof spec == "string") return {name: spec};
+    else return spec || {name: "null"};
+  };
+
+  // Given a mode spec (anything that resolveMode accepts), find and
+  // initialize an actual mode object.
+  CodeMirror.getMode = function(options, spec) {
+    var spec = CodeMirror.resolveMode(spec);
+    var mfactory = modes[spec.name];
+    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
+    var modeObj = mfactory(options, spec);
+    if (modeExtensions.hasOwnProperty(spec.name)) {
+      var exts = modeExtensions[spec.name];
+      for (var prop in exts) {
+        if (!exts.hasOwnProperty(prop)) continue;
+        if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
+        modeObj[prop] = exts[prop];
+      }
+    }
+    modeObj.name = spec.name;
+    if (spec.helperType) modeObj.helperType = spec.helperType;
+    if (spec.modeProps) for (var prop in spec.modeProps)
+      modeObj[prop] = spec.modeProps[prop];
+
+    return modeObj;
+  };
+
+  // Minimal default mode.
+  CodeMirror.defineMode("null", function() {
+    return {token: function(stream) {stream.skipToEnd();}};
+  });
+  CodeMirror.defineMIME("text/plain", "null");
+
+  // This can be used to attach properties to mode objects from
+  // outside the actual mode definition.
+  var modeExtensions = CodeMirror.modeExtensions = {};
+  CodeMirror.extendMode = function(mode, properties) {
+    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+    copyObj(properties, exts);
+  };
+
+  // EXTENSIONS
+
+  CodeMirror.defineExtension = function(name, func) {
+    CodeMirror.prototype[name] = func;
+  };
+  CodeMirror.defineDocExtension = function(name, func) {
+    Doc.prototype[name] = func;
+  };
+  CodeMirror.defineOption = option;
+
+  var initHooks = [];
+  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
+
+  var helpers = CodeMirror.helpers = {};
+  CodeMirror.registerHelper = function(type, name, value) {
+    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
+    helpers[type][name] = value;
+  };
+  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+    CodeMirror.registerHelper(type, name, value);
+    helpers[type]._global.push({pred: predicate, val: value});
+  };
+
+  // MODE STATE HANDLING
+
+  // Utility functions for working with state. Exported because nested
+  // modes need to do this for their inner modes.
+
+  var copyState = CodeMirror.copyState = function(mode, state) {
+    if (state === true) return state;
+    if (mode.copyState) return mode.copyState(state);
+    var nstate = {};
+    for (var n in state) {
+      var val = state[n];
+      if (val instanceof Array) val = val.concat([]);
+      nstate[n] = val;
+    }
+    return nstate;
+  };
+
+  var startState = CodeMirror.startState = function(mode, a1, a2) {
+    return mode.startState ? mode.startState(a1, a2) : true;
+  };
+
+  // Given a mode and a state (for that mode), find the inner mode and
+  // state at the position that the state refers to.
+  CodeMirror.innerMode = function(mode, state) {
+    while (mode.innerMode) {
+      var info = mode.innerMode(state);
+      if (!info || info.mode == mode) break;
+      state = info.state;
+      mode = info.mode;
+    }
+    return info || {mode: mode, state: state};
+  };
+
+  // STANDARD COMMANDS
+
+  // Commands are parameter-less actions that can be performed on an
+  // editor, mostly used for keybindings.
+  var commands = CodeMirror.commands = {
+    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
+    singleSelection: function(cm) {
+      cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
+    },
+    killLine: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        if (range.empty()) {
+          var len = getLine(cm.doc, range.head.line).text.length;
+          if (range.head.ch == len && range.head.line < cm.lastLine())
+            return {from: range.head, to: Pos(range.head.line + 1, 0)};
+          else
+            return {from: range.head, to: Pos(range.head.line, len)};
+        } else {
+          return {from: range.from(), to: range.to()};
+        }
+      });
+    },
+    deleteLine: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        return {from: Pos(range.from().line, 0),
+                to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
+      });
+    },
+    delLineLeft: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        return {from: Pos(range.from().line, 0), to: range.from()};
+      });
+    },
+    delWrappedLineLeft: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        var top = cm.charCoords(range.head, "div").top + 5;
+        var leftPos = cm.coordsChar({left: 0, top: top}, "div");
+        return {from: leftPos, to: range.from()};
+      });
+    },
+    delWrappedLineRight: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        var top = cm.charCoords(range.head, "div").top + 5;
+        var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+        return {from: range.from(), to: rightPos };
+      });
+    },
+    undo: function(cm) {cm.undo();},
+    redo: function(cm) {cm.redo();},
+    undoSelection: function(cm) {cm.undoSelection();},
+    redoSelection: function(cm) {cm.redoSelection();},
+    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
+    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
+    goLineStart: function(cm) {
+      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
+                            {origin: "+move", bias: 1});
+    },
+    goLineStartSmart: function(cm) {
+      cm.extendSelectionsBy(function(range) {
+        return lineStartSmart(cm, range.head);
+      }, {origin: "+move", bias: 1});
+    },
+    goLineEnd: function(cm) {
+      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
+                            {origin: "+move", bias: -1});
+    },
+    goLineRight: function(cm) {
+      cm.extendSelectionsBy(function(range) {
+        var top = cm.charCoords(range.head, "div").top + 5;
+        return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+      }, sel_move);
+    },
+    goLineLeft: function(cm) {
+      cm.extendSelectionsBy(function(range) {
+        var top = cm.charCoords(range.head, "div").top + 5;
+        return cm.coordsChar({left: 0, top: top}, "div");
+      }, sel_move);
+    },
+    goLineLeftSmart: function(cm) {
+      cm.extendSelectionsBy(function(range) {
+        var top = cm.charCoords(range.head, "div").top + 5;
+        var pos = cm.coordsChar({left: 0, top: top}, "div");
+        if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
+        return pos;
+      }, sel_move);
+    },
+    goLineUp: function(cm) {cm.moveV(-1, "line");},
+    goLineDown: function(cm) {cm.moveV(1, "line");},
+    goPageUp: function(cm) {cm.moveV(-1, "page");},
+    goPageDown: function(cm) {cm.moveV(1, "page");},
+    goCharLeft: function(cm) {cm.moveH(-1, "char");},
+    goCharRight: function(cm) {cm.moveH(1, "char");},
+    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
+    goColumnRight: function(cm) {cm.moveH(1, "column");},
+    goWordLeft: function(cm) {cm.moveH(-1, "word");},
+    goGroupRight: function(cm) {cm.moveH(1, "group");},
+    goGroupLeft: function(cm) {cm.moveH(-1, "group");},
+    goWordRight: function(cm) {cm.moveH(1, "word");},
+    delCharBefore: function(cm) {cm.deleteH(-1, "char");},
+    delCharAfter: function(cm) {cm.deleteH(1, "char");},
+    delWordBefore: function(cm) {cm.deleteH(-1, "word");},
+    delWordAfter: function(cm) {cm.deleteH(1, "word");},
+    delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
+    delGroupAfter: function(cm) {cm.deleteH(1, "group");},
+    indentAuto: function(cm) {cm.indentSelection("smart");},
+    indentMore: function(cm) {cm.indentSelection("add");},
+    indentLess: function(cm) {cm.indentSelection("subtract");},
+    insertTab: function(cm) {cm.replaceSelection("\t");},
+    insertSoftTab: function(cm) {
+      var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
+      for (var i = 0; i < ranges.length; i++) {
+        var pos = ranges[i].from();
+        var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
+        spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
+      }
+      cm.replaceSelections(spaces);
+    },
+    defaultTab: function(cm) {
+      if (cm.somethingSelected()) cm.indentSelection("add");
+      else cm.execCommand("insertTab");
+    },
+    transposeChars: function(cm) {
+      runInOp(cm, function() {
+        var ranges = cm.listSelections(), newSel = [];
+        for (var i = 0; i < ranges.length; i++) {
+          var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
+          if (line) {
+            if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
+            if (cur.ch > 0) {
+              cur = new Pos(cur.line, cur.ch + 1);
+              cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
+                              Pos(cur.line, cur.ch - 2), cur, "+transpose");
+            } else if (cur.line > cm.doc.first) {
+              var prev = getLine(cm.doc, cur.line - 1).text;
+              if (prev)
+                cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
+                                Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
+            }
+          }
+          newSel.push(new Range(cur, cur));
+        }
+        cm.setSelections(newSel);
+      });
+    },
+    newlineAndIndent: function(cm) {
+      runInOp(cm, function() {
+        var len = cm.listSelections().length;
+        for (var i = 0; i < len; i++) {
+          var range = cm.listSelections()[i];
+          cm.replaceRange("\n", range.anchor, range.head, "+input");
+          cm.indentLine(range.from().line + 1, null, true);
+          ensureCursorVisible(cm);
+        }
+      });
+    },
+    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
+  };
+
+
+  // STANDARD KEYMAPS
+
+  var keyMap = CodeMirror.keyMap = {};
+
+  keyMap.basic = {
+    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+    "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
+    "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
+    "Esc": "singleSelection"
+  };
+  // Note that the save and find-related commands aren't defined by
+  // default. User code or addons can define them. Unknown commands
+  // are simply ignored.
+  keyMap.pcDefault = {
+    "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+    "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
+    "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+    "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
+    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+    "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
+    fallthrough: "basic"
+  };
+  // Very basic readline/emacs-style bindings, which are standard on Mac.
+  keyMap.emacsy = {
+    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+    "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
+    "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
+  };
+  keyMap.macDefault = {
+    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+    "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
+    "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
+    "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
+    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+    "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
+    "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
+    fallthrough: ["basic", "emacsy"]
+  };
+  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+
+  // KEYMAP DISPATCH
+
+  function normalizeKeyName(name) {
+    var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
+    var alt, ctrl, shift, cmd;
+    for (var i = 0; i < parts.length - 1; i++) {
+      var mod = parts[i];
+      if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
+      else if (/^a(lt)?$/i.test(mod)) alt = true;
+      else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
+      else if (/^s(hift)$/i.test(mod)) shift = true;
+      else throw new Error("Unrecognized modifier name: " + mod);
+    }
+    if (alt) name = "Alt-" + name;
+    if (ctrl) name = "Ctrl-" + name;
+    if (cmd) name = "Cmd-" + name;
+    if (shift) name = "Shift-" + name;
+    return name;
+  }
+
+  // This is a kludge to keep keymaps mostly working as raw objects
+  // (backwards compatibility) while at the same time support features
+  // like normalization and multi-stroke key bindings. It compiles a
+  // new normalized keymap, and then updates the old object to reflect
+  // this.
+  CodeMirror.normalizeKeyMap = function(keymap) {
+    var copy = {};
+    for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
+      var value = keymap[keyname];
+      if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
+      if (value == "...") { delete keymap[keyname]; continue; }
+
+      var keys = map(keyname.split(" "), normalizeKeyName);
+      for (var i = 0; i < keys.length; i++) {
+        var val, name;
+        if (i == keys.length - 1) {
+          name = keys.join(" ");
+          val = value;
+        } else {
+          name = keys.slice(0, i + 1).join(" ");
+          val = "...";
+        }
+        var prev = copy[name];
+        if (!prev) copy[name] = val;
+        else if (prev != val) throw new Error("Inconsistent bindings for " + name);
+      }
+      delete keymap[keyname];
+    }
+    for (var prop in copy) keymap[prop] = copy[prop];
+    return keymap;
+  };
+
+  var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
+    map = getKeyMap(map);
+    var found = map.call ? map.call(key, context) : map[key];
+    if (found === false) return "nothing";
+    if (found === "...") return "multi";
+    if (found != null && handle(found)) return "handled";
+
+    if (map.fallthrough) {
+      if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
+        return lookupKey(key, map.fallthrough, handle, context);
+      for (var i = 0; i < map.fallthrough.length; i++) {
+        var result = lookupKey(key, map.fallthrough[i], handle, context);
+        if (result) return result;
+      }
+    }
+  };
+
+  // Modifier key presses don't count as 'real' key presses for the
+  // purpose of keymap fallthrough.
+  var isModifierKey = CodeMirror.isModifierKey = function(value) {
+    var name = typeof value == "string" ? value : keyNames[value.keyCode];
+    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
+  };
+
+  // Look up the name of a key as indicated by an event object.
+  var keyName = CodeMirror.keyName = function(event, noShift) {
+    if (presto && event.keyCode == 34 && event["char"]) return false;
+    var base = keyNames[event.keyCode], name = base;
+    if (name == null || event.altGraphKey) return false;
+    if (event.altKey && base != "Alt") name = "Alt-" + name;
+    if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
+    if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
+    if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
+    return name;
+  };
+
+  function getKeyMap(val) {
+    return typeof val == "string" ? keyMap[val] : val;
+  }
+
+  // FROMTEXTAREA
+
+  CodeMirror.fromTextArea = function(textarea, options) {
+    options = options ? copyObj(options) : {};
+    options.value = textarea.value;
+    if (!options.tabindex && textarea.tabIndex)
+      options.tabindex = textarea.tabIndex;
+    if (!options.placeholder && textarea.placeholder)
+      options.placeholder = textarea.placeholder;
+    // Set autofocus to true if this textarea is focused, or if it has
+    // autofocus and no other element is focused.
+    if (options.autofocus == null) {
+      var hasFocus = activeElt();
+      options.autofocus = hasFocus == textarea ||
+        textarea.getAttribute("autofocus") != null && hasFocus == document.body;
+    }
+
+    function save() {textarea.value = cm.getValue();}
+    if (textarea.form) {
+      on(textarea.form, "submit", save);
+      // Deplorable hack to make the submit method do the right thing.
+      if (!options.leaveSubmitMethodAlone) {
+        var form = textarea.form, realSubmit = form.submit;
+        try {
+          var wrappedSubmit = form.submit = function() {
+            save();
+            form.submit = realSubmit;
+            form.submit();
+            form.submit = wrappedSubmit;
+          };
+        } catch(e) {}
+      }
+    }
+
+    options.finishInit = function(cm) {
+      cm.save = save;
+      cm.getTextArea = function() { return textarea; };
+      cm.toTextArea = function() {
+        cm.toTextArea = isNaN; // Prevent this from being ran twice
+        save();
+        textarea.parentNode.removeChild(cm.getWrapperElement());
+        textarea.style.display = "";
+        if (textarea.form) {
+          off(textarea.form, "submit", save);
+          if (typeof textarea.form.submit == "function")
+            textarea.form.submit = realSubmit;
+        }
+      };
+    };
+
+    textarea.style.display = "none";
+    var cm = CodeMirror(function(node) {
+      textarea.parentNode.insertBefore(node, textarea.nextSibling);
+    }, options);
+    return cm;
+  };
+
+  // STRING STREAM
+
+  // Fed to the mode parsers, provides helper functions to make
+  // parsers more succinct.
+
+  var StringStream = CodeMirror.StringStream = function(string, tabSize) {
+    this.pos = this.start = 0;
+    this.string = string;
+    this.tabSize = tabSize || 8;
+    this.lastColumnPos = this.lastColumnValue = 0;
+    this.lineStart = 0;
+  };
+
+  StringStream.prototype = {
+    eol: function() {return this.pos >= this.string.length;},
+    sol: function() {return this.pos == this.lineStart;},
+    peek: function() {return this.string.charAt(this.pos) || undefined;},
+    next: function() {
+      if (this.pos < this.string.length)
+        return this.string.charAt(this.pos++);
+    },
+    eat: function(match) {
+      var ch = this.string.charAt(this.pos);
+      if (typeof match == "string") var ok = ch == match;
+      else var ok = ch && (match.test ? match.test(ch) : match(ch));
+      if (ok) {++this.pos; return ch;}
+    },
+    eatWhile: function(match) {
+      var start = this.pos;
+      while (this.eat(match)){}
+      return this.pos > start;
+    },
+    eatSpace: function() {
+      var start = this.pos;
+      while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
+      return this.pos > start;
+    },
+    skipToEnd: function() {this.pos = this.string.length;},
+    skipTo: function(ch) {
+      var found = this.string.indexOf(ch, this.pos);
+      if (found > -1) {this.pos = found; return true;}
+    },
+    backUp: function(n) {this.pos -= n;},
+    column: function() {
+      if (this.lastColumnPos < this.start) {
+        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+        this.lastColumnPos = this.start;
+      }
+      return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+    },
+    indentation: function() {
+      return countColumn(this.string, null, this.tabSize) -
+        (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+    },
+    match: function(pattern, consume, caseInsensitive) {
+      if (typeof pattern == "string") {
+        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
+        var substr = this.string.substr(this.pos, pattern.length);
+        if (cased(substr) == cased(pattern)) {
+          if (consume !== false) this.pos += pattern.length;
+          return true;
+        }
+      } else {
+        var match = this.string.slice(this.pos).match(pattern);
+        if (match && match.index > 0) return null;
+        if (match && consume !== false) this.pos += match[0].length;
+        return match;
+      }
+    },
+    current: function(){return this.string.slice(this.start, this.pos);},
+    hideFirstChars: function(n, inner) {
+      this.lineStart += n;
+      try { return inner(); }
+      finally { this.lineStart -= n; }
+    }
+  };
+
+  // TEXTMARKERS
+
+  // Created with markText and setBookmark methods. A TextMarker is a
+  // handle that can be used to clear or find a marked position in the
+  // document. Line objects hold arrays (markedSpans) containing
+  // {from, to, marker} object pointing to such marker objects, and
+  // indicating that such a marker is present on that line. Multiple
+  // lines may point to the same marker when it spans across lines.
+  // The spans will have null for their from/to properties when the
+  // marker continues beyond the start/end of the line. Markers have
+  // links back to the lines they currently touch.
+
+  var nextMarkerId = 0;
+
+  var TextMarker = CodeMirror.TextMarker = function(doc, type) {
+    this.lines = [];
+    this.type = type;
+    this.doc = doc;
+    this.id = ++nextMarkerId;
+  };
+  eventMixin(TextMarker);
+
+  // Clear the marker.
+  TextMarker.prototype.clear = function() {
+    if (this.explicitlyCleared) return;
+    var cm = this.doc.cm, withOp = cm && !cm.curOp;
+    if (withOp) startOperation(cm);
+    if (hasHandler(this, "clear")) {
+      var found = this.find();
+      if (found) signalLater(this, "clear", found.from, found.to);
+    }
+    var min = null, max = null;
+    for (var i = 0; i < this.lines.length; ++i) {
+      var line = this.lines[i];
+      var span = getMarkedSpanFor(line.markedSpans, this);
+      if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
+      else if (cm) {
+        if (span.to != null) max = lineNo(line);
+        if (span.from != null) min = lineNo(line);
+      }
+      line.markedSpans = removeMarkedSpan(line.markedSpans, span);
+      if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
+        updateLineHeight(line, textHeight(cm.display));
+    }
+    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
+      var visual = visualLine(this.lines[i]), len = lineLength(visual);
+      if (len > cm.display.maxLineLength) {
+        cm.display.maxLine = visual;
+        cm.display.maxLineLength = len;
+        cm.display.maxLineChanged = true;
+      }
+    }
+
+    if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
+    this.lines.length = 0;
+    this.explicitlyCleared = true;
+    if (this.atomic && this.doc.cantEdit) {
+      this.doc.cantEdit = false;
+      if (cm) reCheckSelection(cm.doc);
+    }
+    if (cm) signalLater(cm, "markerCleared", cm, this);
+    if (withOp) endOperation(cm);
+    if (this.parent) this.parent.clear();
+  };
+
+  // Find the position of the marker in the document. Returns a {from,
+  // to} object by default. Side can be passed to get a specific side
+  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
+  // Pos objects returned contain a line object, rather than a line
+  // number (used to prevent looking up the same line twice).
+  TextMarker.prototype.find = function(side, lineObj) {
+    if (side == null && this.type == "bookmark") side = 1;
+    var from, to;
+    for (var i = 0; i < this.lines.length; ++i) {
+      var line = this.lines[i];
+      var span = getMarkedSpanFor(line.markedSpans, this);
+      if (span.from != null) {
+        from = Pos(lineObj ? line : lineNo(line), span.from);
+        if (side == -1) return from;
+      }
+      if (span.to != null) {
+        to = Pos(lineObj ? line : lineNo(line), span.to);
+        if (side == 1) return to;
+      }
+    }
+    return from && {from: from, to: to};
+  };
+
+  // Signals that the marker's widget changed, and surrounding layout
+  // should be recomputed.
+  TextMarker.prototype.changed = function() {
+    var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
+    if (!pos || !cm) return;
+    runInOp(cm, function() {
+      var line = pos.line, lineN = lineNo(pos.line);
+      var view = findViewForLine(cm, lineN);
+      if (view) {
+        clearLineMeasurementCacheFor(view);
+        cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
+      }
+      cm.curOp.updateMaxLine = true;
+      if (!lineIsHidden(widget.doc, line) && widget.height != null) {
+        var oldHeight = widget.height;
+        widget.height = null;
+        var dHeight = widgetHeight(widget) - oldHeight;
+        if (dHeight)
+          updateLineHeight(line, line.height + dHeight);
+      }
+    });
+  };
+
+  TextMarker.prototype.attachLine = function(line) {
+    if (!this.lines.length && this.doc.cm) {
+      var op = this.doc.cm.curOp;
+      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
+        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
+    }
+    this.lines.push(line);
+  };
+  TextMarker.prototype.detachLine = function(line) {
+    this.lines.splice(indexOf(this.lines, line), 1);
+    if (!this.lines.length && this.doc.cm) {
+      var op = this.doc.cm.curOp;
+      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
+    }
+  };
+
+  // Collapsed markers have unique ids, in order to be able to order
+  // them, which is needed for uniquely determining an outer marker
+  // when they overlap (they may nest, but not partially overlap).
+  var nextMarkerId = 0;
+
+  // Create a marker, wire it up to the right lines, and
+  function markText(doc, from, to, options, type) {
+    // Shared markers (across linked documents) are handled separately
+    // (markTextShared will call out to this again, once per
+    // document).
+    if (options && options.shared) return markTextShared(doc, from, to, options, type);
+    // Ensure we are in an operation.
+    if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
+
+    var marker = new TextMarker(doc, type), diff = cmp(from, to);
+    if (options) copyObj(options, marker, false);
+    // Don't connect empty markers unless clearWhenEmpty is false
+    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
+      return marker;
+    if (marker.replacedWith) {
+      // Showing up as a widget implies collapsed (widget replaces text)
+      marker.collapsed = true;
+      marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
+      if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
+      if (options.insertLeft) marker.widgetNode.insertLeft = true;
+    }
+    if (marker.collapsed) {
+      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+        throw new Error("Inserting collapsed marker partially overlapping an existing one");
+      sawCollapsedSpans = true;
+    }
+
+    if (marker.addToHistory)
+      addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
+
+    var curLine = from.line, cm = doc.cm, updateMaxLine;
+    doc.iter(curLine, to.line + 1, function(line) {
+      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
+        updateMaxLine = true;
+      if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
+      addMarkedSpan(line, new MarkedSpan(marker,
+                                         curLine == from.line ? from.ch : null,
+                                         curLine == to.line ? to.ch : null));
+      ++curLine;
+    });
+    // lineIsHidden depends on the presence of the spans, so needs a second pass
+    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
+      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
+    });
+
+    if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
+
+    if (marker.readOnly) {
+      sawReadOnlySpans = true;
+      if (doc.history.done.length || doc.history.undone.length)
+        doc.clearHistory();
+    }
+    if (marker.collapsed) {
+      marker.id = ++nextMarkerId;
+      marker.atomic = true;
+    }
+    if (cm) {
+      // Sync editor state
+      if (updateMaxLine) cm.curOp.updateMaxLine = true;
+      if (marker.collapsed)
+        regChange(cm, from.line, to.line + 1);
+      else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
+        for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
+      if (marker.atomic) reCheckSelection(cm.doc);
+      signalLater(cm, "markerAdded", cm, marker);
+    }
+    return marker;
+  }
+
+  // SHARED TEXTMARKERS
+
+  // A shared marker spans multiple linked documents. It is
+  // implemented as a meta-marker-object controlling multiple normal
+  // markers.
+  var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
+    this.markers = markers;
+    this.primary = primary;
+    for (var i = 0; i < markers.length; ++i)
+      markers[i].parent = this;
+  };
+  eventMixin(SharedTextMarker);
+
+  SharedTextMarker.prototype.clear = function() {
+    if (this.explicitlyCleared) return;
+    this.explicitlyCleared = true;
+    for (var i = 0; i < this.markers.length; ++i)
+      this.markers[i].clear();
+    signalLater(this, "clear");
+  };
+  SharedTextMarker.prototype.find = function(side, lineObj) {
+    return this.primary.find(side, lineObj);
+  };
+
+  function markTextShared(doc, from, to, options, type) {
+    options = copyObj(options);
+    options.shared = false;
+    var markers = [markText(doc, from, to, options, type)], primary = markers[0];
+    var widget = options.widgetNode;
+    linkedDocs(doc, function(doc) {
+      if (widget) options.widgetNode = widget.cloneNode(true);
+      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
+      for (var i = 0; i < doc.linked.length; ++i)
+        if (doc.linked[i].isParent) return;
+      primary = lst(markers);
+    });
+    return new SharedTextMarker(markers, primary);
+  }
+
+  function findSharedMarkers(doc) {
+    return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
+                         function(m) { return m.parent; });
+  }
+
+  function copySharedMarkers(doc, markers) {
+    for (var i = 0; i < markers.length; i++) {
+      var marker = markers[i], pos = marker.find();
+      var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
+      if (cmp(mFrom, mTo)) {
+        var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
+        marker.markers.push(subMark);
+        subMark.parent = marker;
+      }
+    }
+  }
+
+  function detachSharedMarkers(markers) {
+    for (var i = 0; i < markers.length; i++) {
+      var marker = markers[i], linked = [marker.primary.doc];;
+      linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
+      for (var j = 0; j < marker.markers.length; j++) {
+        var subMarker = marker.markers[j];
+        if (indexOf(linked, subMarker.doc) == -1) {
+          subMarker.parent = null;
+          marker.markers.splice(j--, 1);
+        }
+      }
+    }
+  }
+
+  // TEXTMARKER SPANS
+
+  function MarkedSpan(marker, from, to) {
+    this.marker = marker;
+    this.from = from; this.to = to;
+  }
+
+  // Search an array of spans for a span matching the given marker.
+  function getMarkedSpanFor(spans, marker) {
+    if (spans) for (var i = 0; i < spans.length; ++i) {
+      var span = spans[i];
+      if (span.marker == marker) return span;
+    }
+  }
+  // Remove a span from an array, returning undefined if no spans are
+  // left (we don't store arrays for lines without spans).
+  function removeMarkedSpan(spans, span) {
+    for (var r, i = 0; i < spans.length; ++i)
+      if (spans[i] != span) (r || (r = [])).push(spans[i]);
+    return r;
+  }
+  // Add a span to a line.
+  function addMarkedSpan(line, span) {
+    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
+    span.marker.attachLine(line);
+  }
+
+  // Used for the algorithm that adjusts markers for a change in the
+  // document. These functions cut an array of spans at a given
+  // character position, returning an array of remaining chunks (or
+  // undefined if nothing remains).
+  function markedSpansBefore(old, startCh, isInsert) {
+    if (old) for (var i = 0, nw; i < old.length; ++i) {
+      var span = old[i], marker = span.marker;
+      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
+      if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
+        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
+        (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
+      }
+    }
+    return nw;
+  }
+  function markedSpansAfter(old, endCh, isInsert) {
+    if (old) for (var i = 0, nw; i < old.length; ++i) {
+      var span = old[i], marker = span.marker;
+      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
+      if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
+        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
+        (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
+                                              span.to == null ? null : span.to - endCh));
+      }
+    }
+    return nw;
+  }
+
+  // Given a change object, compute the new set of marker spans that
+  // cover the line in which the change took place. Removes spans
+  // entirely within the change, reconnects spans belonging to the
+  // same marker that appear on both sides of the change, and cuts off
+  // spans partially within the change. Returns an array of span
+  // arrays with one element for each line in (after) the change.
+  function stretchSpansOverChange(doc, change) {
+    if (change.full) return null;
+    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
+    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
+    if (!oldFirst && !oldLast) return null;
+
+    var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
+    // Get the spans that 'stick out' on both sides
+    var first = markedSpansBefore(oldFirst, startCh, isInsert);
+    var last = markedSpansAfter(oldLast, endCh, isInsert);
+
+    // Next, merge those two ends
+    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
+    if (first) {
+      // Fix up .to properties of first
+      for (var i = 0; i < first.length; ++i) {
+        var span = first[i];
+        if (span.to == null) {
+          var found = getMarkedSpanFor(last, span.marker);
+          if (!found) span.to = startCh;
+          else if (sameLine) span.to = found.to == null ? null : found.to + offset;
+        }
+      }
+    }
+    if (last) {
+      // Fix up .from in last (or move them into first in case of sameLine)
+      for (var i = 0; i < last.length; ++i) {
+        var span = last[i];
+        if (span.to != null) span.to += offset;
+        if (span.from == null) {
+          var found = getMarkedSpanFor(first, span.marker);
+          if (!found) {
+            span.from = offset;
+            if (sameLine) (first || (first = [])).push(span);
+          }
+        } else {
+          span.from += offset;
+          if (sameLine) (first || (first = [])).push(span);
+        }
+      }
+    }
+    // Make sure we didn't create any zero-length spans
+    if (first) first = clearEmptySpans(first);
+    if (last && last != first) last = clearEmptySpans(last);
+
+    var newMarkers = [first];
+    if (!sameLine) {
+      // Fill gap with whole-line-spans
+      var gap = change.text.length - 2, gapMarkers;
+      if (gap > 0 && first)
+        for (var i = 0; i < first.length; ++i)
+          if (first[i].to == null)
+            (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
+      for (var i = 0; i < gap; ++i)
+        newMarkers.push(gapMarkers);
+      newMarkers.push(last);
+    }
+    return newMarkers;
+  }
+
+  // Remove spans that are empty and don't have a clearWhenEmpty
+  // option of false.
+  function clearEmptySpans(spans) {
+    for (var i = 0; i < spans.length; ++i) {
+      var span = spans[i];
+      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+        spans.splice(i--, 1);
+    }
+    if (!spans.length) return null;
+    return spans;
+  }
+
+  // Used for un/re-doing changes from the history. Combines the
+  // result of computing the existing spans with the set of spans that
+  // existed in the history (so that deleting around a span and then
+  // undoing brings back the span).
+  function mergeOldSpans(doc, change) {
+    var old = getOldSpans(doc, change);
+    var stretched = stretchSpansOverChange(doc, change);
+    if (!old) return stretched;
+    if (!stretched) return old;
+
+    for (var i = 0; i < old.length; ++i) {
+      var oldCur = old[i], stretchCur = stretched[i];
+      if (oldCur && stretchCur) {
+        spans: for (var j = 0; j < stretchCur.length; ++j) {
+          var span = stretchCur[j];
+          for (var k = 0; k < oldCur.length; ++k)
+            if (oldCur[k].marker == span.marker) continue spans;
+          oldCur.push(span);
+        }
+      } else if (stretchCur) {
+        old[i] = stretchCur;
+      }
+    }
+    return old;
+  }
+
+  // Used to 'clip' out readOnly ranges when making a change.
+  function removeReadOnlyRanges(doc, from, to) {
+    var markers = null;
+    doc.iter(from.line, to.line + 1, function(line) {
+      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
+        var mark = line.markedSpans[i].marker;
+        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
+          (markers || (markers = [])).push(mark);
+      }
+    });
+    if (!markers) return null;
+    var parts = [{from: from, to: to}];
+    for (var i = 0; i < markers.length; ++i) {
+      var mk = markers[i], m = mk.find(0);
+      for (var j = 0; j < parts.length; ++j) {
+        var p = parts[j];
+        if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
+        var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
+        if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
+          newParts.push({from: p.from, to: m.from});
+        if (dto > 0 || !mk.inclusiveRight && !dto)
+          newParts.push({from: m.to, to: p.to});
+        parts.splice.apply(parts, newParts);
+        j += newParts.length - 1;
+      }
+    }
+    return parts;
+  }
+
+  // Connect or disconnect spans from a line.
+  function detachMarkedSpans(line) {
+    var spans = line.markedSpans;
+    if (!spans) return;
+    for (var i = 0; i < spans.length; ++i)
+      spans[i].marker.detachLine(line);
+    line.markedSpans = null;
+  }
+  function attachMarkedSpans(line, spans) {
+    if (!spans) return;
+    for (var i = 0; i < spans.length; ++i)
+      spans[i].marker.attachLine(line);
+    line.markedSpans = spans;
+  }
+
+  // Helpers used when computing which overlapping collapsed span
+  // counts as the larger one.
+  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
+  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
+
+  // Returns a number indicating which of two overlapping collapsed
+  // spans is larger (and thus includes the other). Falls back to
+  // comparing ids when the spans cover exactly the same range.
+  function compareCollapsedMarkers(a, b) {
+    var lenDiff = a.lines.length - b.lines.length;
+    if (lenDiff != 0) return lenDiff;
+    var aPos = a.find(), bPos = b.find();
+    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+    if (fromCmp) return -fromCmp;
+    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+    if (toCmp) return toCmp;
+    return b.id - a.id;
+  }
+
+  // Find out whether a line ends or starts in a collapsed span. If
+  // so, return the marker for that span.
+  function collapsedSpanAtSide(line, start) {
+    var sps = sawCollapsedSpans && line.markedSpans, found;
+    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+      sp = sps[i];
+      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+          (!found || compareCollapsedMarkers(found, sp.marker) < 0))
+        found = sp.marker;
+    }
+    return found;
+  }
+  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
+  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
+
+  // Test whether there exists a collapsed span that partially
+  // overlaps (covers the start or end, but not both) of a new span.
+  // Such overlap is not allowed.
+  function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
+    var line = getLine(doc, lineNo);
+    var sps = sawCollapsedSpans && line.markedSpans;
+    if (sps) for (var i = 0; i < sps.length; ++i) {
+      var sp = sps[i];
+      if (!sp.marker.collapsed) continue;
+      var found = sp.marker.find(0);
+      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
+      if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
+          fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
+        return true;
+    }
+  }
+
+  // A visual line is a line as drawn on the screen. Folding, for
+  // example, can cause multiple logical lines to appear on the same
+  // visual line. This finds the start of the visual line that the
+  // given line is part of (usually that is the line itself).
+  function visualLine(line) {
+    var merged;
+    while (merged = collapsedSpanAtStart(line))
+      line = merged.find(-1, true).line;
+    return line;
+  }
+
+  // Returns an array of logical lines that continue the visual line
+  // started by the argument, or undefined if there are no such lines.
+  function visualLineContinued(line) {
+    var merged, lines;
+    while (merged = collapsedSpanAtEnd(line)) {
+      line = merged.find(1, true).line;
+      (lines || (lines = [])).push(line);
+    }
+    return lines;
+  }
+
+  // Get the line number of the start of the visual line that the
+  // given line number is part of.
+  function visualLineNo(doc, lineN) {
+    var line = getLine(doc, lineN), vis = visualLine(line);
+    if (line == vis) return lineN;
+    return lineNo(vis);
+  }
+  // Get the line number of the start of the next visual line after
+  // the given line.
+  function visualLineEndNo(doc, lineN) {
+    if (lineN > doc.lastLine()) return lineN;
+    var line = getLine(doc, lineN), merged;
+    if (!lineIsHidden(doc, line)) return lineN;
+    while (merged = collapsedSpanAtEnd(line))
+      line = merged.find(1, true).line;
+    return lineNo(line) + 1;
+  }
+
+  // Compute whether a line is hidden. Lines count as hidden when they
+  // are part of a visual line that starts with another line, or when
+  // they are entirely covered by collapsed, non-widget span.
+  function lineIsHidden(doc, line) {
+    var sps = sawCollapsedSpans && line.markedSpans;
+    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+      sp = sps[i];
+      if (!sp.marker.collapsed) continue;
+      if (sp.from == null) return true;
+      if (sp.marker.widgetNode) continue;
+      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
+        return true;
+    }
+  }
+  function lineIsHiddenInner(doc, line, span) {
+    if (span.to == null) {
+      var end = span.marker.find(1, true);
+      return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
+    }
+    if (span.marker.inclusiveRight && span.to == line.text.length)
+      return true;
+    for (var sp, i = 0; i < line.markedSpans.length; ++i) {
+      sp = line.markedSpans[i];
+      if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
+          (sp.to == null || sp.to != span.from) &&
+          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
+          lineIsHiddenInner(doc, line, sp)) return true;
+    }
+  }
+
+  // LINE WIDGETS
+
+  // Line widgets are block elements displayed above or below a line.
+
+  var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
+    if (options) for (var opt in options) if (options.hasOwnProperty(opt))
+      this[opt] = options[opt];
+    this.doc = doc;
+    this.node = node;
+  };
+  eventMixin(LineWidget);
+
+  function adjustScrollWhenAboveVisible(cm, line, diff) {
+    if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
+      addToScrollPos(cm, null, diff);
+  }
+
+  LineWidget.prototype.clear = function() {
+    var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
+    if (no == null || !ws) return;
+    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
+    if (!ws.length) line.widgets = null;
+    var height = widgetHeight(this);
+    updateLineHeight(line, Math.max(0, line.height - height));
+    if (cm) runInOp(cm, function() {
+      adjustScrollWhenAboveVisible(cm, line, -height);
+      regLineChange(cm, no, "widget");
+    });
+  };
+  LineWidget.prototype.changed = function() {
+    var oldH = this.height, cm = this.doc.cm, line = this.line;
+    this.height = null;
+    var diff = widgetHeight(this) - oldH;
+    if (!diff) return;
+    updateLineHeight(line, line.height + diff);
+    if (cm) runInOp(cm, function() {
+      cm.curOp.forceUpdate = true;
+      adjustScrollWhenAboveVisible(cm, line, diff);
+    });
+  };
+
+  function widgetHeight(widget) {
+    if (widget.height != null) return widget.height;
+    var cm = widget.doc.cm;
+    if (!cm) return 0;
+    if (!contains(document.body, widget.node)) {
+      var parentStyle = "position: relative;";
+      if (widget.coverGutter)
+        parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
+      if (widget.noHScroll)
+        parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
+      removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
+    }
+    return widget.height = widget.node.offsetHeight;
+  }
+
+  function addLineWidget(doc, handle, node, options) {
+    var widget = new LineWidget(doc, node, options);
+    var cm = doc.cm;
+    if (cm && widget.noHScroll) cm.display.alignWidgets = true;
+    changeLine(doc, handle, "widget", function(line) {
+      var widgets = line.widgets || (line.widgets = []);
+      if (widget.insertAt == null) widgets.push(widget);
+      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
+      widget.line = line;
+      if (cm && !lineIsHidden(doc, line)) {
+        var aboveVisible = heightAtLine(line) < doc.scrollTop;
+        updateLineHeight(line, line.height + widgetHeight(widget));
+        if (aboveVisible) addToScrollPos(cm, null, widget.height);
+        cm.curOp.forceUpdate = true;
+      }
+      return true;
+    });
+    return widget;
+  }
+
+  // LINE DATA STRUCTURE
+
+  // Line objects. These hold state related to a line, including
+  // highlighting info (the styles array).
+  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
+    this.text = text;
+    attachMarkedSpans(this, markedSpans);
+    this.height = estimateHeight ? estimateHeight(this) : 1;
+  };
+  eventMixin(Line);
+  Line.prototype.lineNo = function() { return lineNo(this); };
+
+  // Change the content (text, markers) of a line. Automatically
+  // invalidates cached information and tries to re-estimate the
+  // line's height.
+  function updateLine(line, text, markedSpans, estimateHeight) {
+    line.text = text;
+    if (line.stateAfter) line.stateAfter = null;
+    if (line.styles) line.styles = null;
+    if (line.order != null) line.order = null;
+    detachMarkedSpans(line);
+    attachMarkedSpans(line, markedSpans);
+    var estHeight = estimateHeight ? estimateHeight(line) : 1;
+    if (estHeight != line.height) updateLineHeight(line, estHeight);
+  }
+
+  // Detach a line from the document tree and its markers.
+  function cleanUpLine(line) {
+    line.parent = null;
+    detachMarkedSpans(line);
+  }
+
+  function extractLineClasses(type, output) {
+    if (type) for (;;) {
+      var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
+      if (!lineClass) break;
+      type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
+      var prop = lineClass[1] ? "bgClass" : "textClass";
+      if (output[prop] == null)
+        output[prop] = lineClass[2];
+      else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
+        output[prop] += " " + lineClass[2];
+    }
+    return type;
+  }
+
+  function callBlankLine(mode, state) {
+    if (mode.blankLine) return mode.blankLine(state);
+    if (!mode.innerMode) return;
+    var inner = CodeMirror.innerMode(mode, state);
+    if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
+  }
+
+  function readToken(mode, stream, state, inner) {
+    for (var i = 0; i < 10; i++) {
+      if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
+      var style = mode.token(stream, state);
+      if (stream.pos > stream.start) return style;
+    }
+    throw new Error("Mode " + mode.name + " failed to advance stream.");
+  }
+
+  // Utility for getTokenAt and getLineTokens
+  function takeToken(cm, pos, precise, asArray) {
+    function getObj(copy) {
+      return {start: stream.start, end: stream.pos,
+              string: stream.current(),
+              type: style || null,
+              state: copy ? copyState(doc.mode, state) : state};
+    }
+
+    var doc = cm.doc, mode = doc.mode, style;
+    pos = clipPos(doc, pos);
+    var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
+    var stream = new StringStream(line.text, cm.options.tabSize), tokens;
+    if (asArray) tokens = [];
+    while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
+      stream.start = stream.pos;
+      style = readToken(mode, stream, state);
+      if (asArray) tokens.push(getObj(true));
+    }
+    return asArray ? tokens : getObj();
+  }
+
+  // Run the given mode's parser over a line, calling f for each token.
+  function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
+    var flattenSpans = mode.flattenSpans;
+    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
+    var curStart = 0, curStyle = null;
+    var stream = new StringStream(text, cm.options.tabSize), style;
+    var inner = cm.options.addModeClass && [null];
+    if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
+    while (!stream.eol()) {
+      if (stream.pos > cm.options.maxHighlightLength) {
+        flattenSpans = false;
+        if (forceToEnd) processLine(cm, text, state, stream.pos);
+        stream.pos = text.length;
+        style = null;
+      } else {
+        style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
+      }
+      if (inner) {
+        var mName = inner[0].name;
+        if (mName) style = "m-" + (style ? mName + " " + style : mName);
+      }
+      if (!flattenSpans || curStyle != style) {
+        while (curStart < stream.start) {
+          curStart = Math.min(stream.start, curStart + 50000);
+          f(curStart, curStyle);
+        }
+        curStyle = style;
+      }
+      stream.start = stream.pos;
+    }
+    while (curStart < stream.pos) {
+      // Webkit seems to refuse to render text nodes longer than 57444 characters
+      var pos = Math.min(stream.pos, curStart + 50000);
+      f(pos, curStyle);
+      curStart = pos;
+    }
+  }
+
+  // Compute a style array (an array starting with a mode generation
+  // -- for invalidation -- followed by pairs of end positions and
+  // style strings), which is used to highlight the tokens on the
+  // line.
+  function highlightLine(cm, line, state, forceToEnd) {
+    // A styles array always starts with a number identifying the
+    // mode/overlays that it is based on (for easy invalidation).
+    var st = [cm.state.modeGen], lineClasses = {};
+    // Compute the base array of styles
+    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
+      st.push(end, style);
+    }, lineClasses, forceToEnd);
+
+    // Run overlays, adjust style array.
+    for (var o = 0; o < cm.state.overlays.length; ++o) {
+      var overlay = cm.state.overlays[o], i = 1, at = 0;
+      runMode(cm, line.text, overlay.mode, true, function(end, style) {
+        var start = i;
+        // Ensure there's a token end at the current position, and that i points at it
+        while (at < end) {
+          var i_end = st[i];
+          if (i_end > end)
+            st.splice(i, 1, end, st[i+1], i_end);
+          i += 2;
+          at = Math.min(end, i_end);
+        }
+        if (!style) return;
+        if (overlay.opaque) {
+          st.splice(start, i - start, end, "cm-overlay " + style);
+          i = start + 2;
+        } else {
+          for (; start < i; start += 2) {
+            var cur = st[start+1];
+            st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
+          }
+        }
+      }, lineClasses);
+    }
+
+    return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
+  }
+
+  function getLineStyles(cm, line, updateFrontier) {
+    if (!line.styles || line.styles[0] != cm.state.modeGen) {
+      var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+      line.styles = result.styles;
+      if (result.classes) line.styleClasses = result.classes;
+      else if (line.styleClasses) line.styleClasses = null;
+      if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
+    }
+    return line.styles;
+  }
+
+  // Lightweight form of highlight -- proceed over this line and
+  // update state, but don't save a style array. Used for lines that
+  // aren't currently visible.
+  function processLine(cm, text, state, startAt) {
+    var mode = cm.doc.mode;
+    var stream = new StringStream(text, cm.options.tabSize);
+    stream.start = stream.pos = startAt || 0;
+    if (text == "") callBlankLine(mode, state);
+    while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
+      readToken(mode, stream, state);
+      stream.start = stream.pos;
+    }
+  }
+
+  // Convert a style as returned by a mode (either null, or a string
+  // containing one or more styles) to a CSS style. This is cached,
+  // and also looks for line-wide styles.
+  var styleToClassCache = {}, styleToClassCacheWithMode = {};
+  function interpretTokenStyle(style, options) {
+    if (!style || /^\s*$/.test(style)) return null;
+    var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+    return cache[style] ||
+      (cache[style] = style.replace(/\S+/g, "cm-$&"));
+  }
+
+  // Render the DOM representation of the text of a line. Also builds
+  // up a 'line map', which points at the DOM nodes that represent
+  // specific stretches of text, and is used by the measuring code.
+  // The returned object contains the DOM node, this map, and
+  // information about line-wide styles that were set by the mode.
+  function buildLineContent(cm, lineView) {
+    // The padding-right forces the element to have a 'border', which
+    // is needed on Webkit to be able to get line-level bounding
+    // rectangles for it (in measureChar).
+    var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
+    var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
+                   col: 0, pos: 0, cm: cm,
+                   splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
+    lineView.measure = {};
+
+    // Iterate over the logical lines that make up this visual line.
+    for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
+      var line = i ? lineView.rest[i - 1] : lineView.line, order;
+      builder.pos = 0;
+      builder.addToken = buildToken;
+      // Optionally wire in some hacks into the token-rendering
+      // algorithm, to deal with browser quirks.
+      if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
+        builder.addToken = buildTokenBadBidi(builder.addToken, order);
+      builder.map = [];
+      var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
+      insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
+      if (line.styleClasses) {
+        if (line.styleClasses.bgClass)
+          builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
+        if (line.styleClasses.textClass)
+          builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
+      }
+
+      // Ensure at least a single node is present, for measuring.
+      if (builder.map.length == 0)
+        builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
+
+      // Store the map and a cache object for the current logical line
+      if (i == 0) {
+        lineView.measure.map = builder.map;
+        lineView.measure.cache = {};
+      } else {
+        (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
+        (lineView.measure.caches || (lineView.measure.caches = [])).push({});
+      }
+    }
+
+    // See issue #2901
+    if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
+      builder.content.className = "cm-tab-wrap-hack";
+
+    signal(cm, "renderLine", cm, lineView.line, builder.pre);
+    if (builder.pre.className)
+      builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
+
+    return builder;
+  }
+
+  function defaultSpecialCharPlaceholder(ch) {
+    var token = elt("span", "\u2022", "cm-invalidchar");
+    token.title = "\\u" + ch.charCodeAt(0).toString(16);
+    token.setAttribute("aria-label", token.title);
+    return token;
+  }
+
+  // Build up the DOM representation for a single token, and add it to
+  // the line map. Takes care to render special characters separately.
+  function buildToken(builder, text, style, startStyle, endStyle, title, css) {
+    if (!text) return;
+    var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
+    var special = builder.cm.state.specialChars, mustWrap = false;
+    if (!special.test(text)) {
+      builder.col += text.length;
+      var content = document.createTextNode(displayText);
+      builder.map.push(builder.pos, builder.pos + text.length, content);
+      if (ie && ie_version < 9) mustWrap = true;
+      builder.pos += text.length;
+    } else {
+      var content = document.createDocumentFragment(), pos = 0;
+      while (true) {
+        special.lastIndex = pos;
+        var m = special.exec(text);
+        var skipped = m ? m.index - pos : text.length - pos;
+        if (skipped) {
+          var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
+          if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+          else content.appendChild(txt);
+          builder.map.push(builder.pos, builder.pos + skipped, txt);
+          builder.col += skipped;
+          builder.pos += skipped;
+        }
+        if (!m) break;
+        pos += skipped + 1;
+        if (m[0] == "\t") {
+          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
+          var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
+          txt.setAttribute("role", "presentation");
+          txt.setAttribute("cm-text", "\t");
+          builder.col += tabWidth;
+        } else {
+          var txt = builder.cm.options.specialCharPlaceholder(m[0]);
+          txt.setAttribute("cm-text", m[0]);
+          if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+          else content.appendChild(txt);
+          builder.col += 1;
+        }
+        builder.map.push(builder.pos, builder.pos + 1, txt);
+        builder.pos++;
+      }
+    }
+    if (style || startStyle || endStyle || mustWrap || css) {
+      var fullStyle = style || "";
+      if (startStyle) fullStyle += startStyle;
+      if (endStyle) fullStyle += endStyle;
+      var token = elt("span", [content], fullStyle, css);
+      if (title) token.title = title;
+      return builder.content.appendChild(token);
+    }
+    builder.content.appendChild(content);
+  }
+
+  function splitSpaces(old) {
+    var out = " ";
+    for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
+    out += " ";
+    return out;
+  }
+
+  // Work around nonsense dimensions being reported for stretches of
+  // right-to-left text.
+  function buildTokenBadBidi(inner, order) {
+    return function(builder, text, style, startStyle, endStyle, title, css) {
+      style = style ? style + " cm-force-border" : "cm-force-border";
+      var start = builder.pos, end = start + text.length;
+      for (;;) {
+        // Find the part that overlaps with the start of this text
+        for (var i = 0; i < order.length; i++) {
+          var part = order[i];
+          if (part.to > start && part.from <= start) break;
+        }
+        if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
+        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
+        startStyle = null;
+        text = text.slice(part.to - start);
+        start = part.to;
+      }
+    };
+  }
+
+  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
+    var widget = !ignoreWidget && marker.widgetNode;
+    if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
+    if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
+      if (!widget)
+        widget = builder.content.appendChild(document.createElement("span"));
+      widget.setAttribute("cm-marker", marker.id);
+    }
+    if (widget) {
+      builder.cm.display.input.setUneditable(widget);
+      builder.content.appendChild(widget);
+    }
+    builder.pos += size;
+  }
+
+  // Outputs a number of spans to make up a line, taking highlighting
+  // and marked text into account.
+  function insertLineContent(line, builder, styles) {
+    var spans = line.markedSpans, allText = line.text, at = 0;
+    if (!spans) {
+      for (var i = 1; i < styles.length; i+=2)
+        builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
+      return;
+    }
+
+    var len = allText.length, pos = 0, i = 1, text = "", style, css;
+    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
+    for (;;) {
+      if (nextChange == pos) { // Update current marker set
+        spanStyle = spanEndStyle = spanStartStyle = title = css = "";
+        collapsed = null; nextChange = Infinity;
+        var foundBookmarks = [];
+        for (var j = 0; j < spans.length; ++j) {
+          var sp = spans[j], m = sp.marker;
+          if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
+            foundBookmarks.push(m);
+          } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
+            if (sp.to != null && sp.to != pos && nextChange > sp.to) {
+              nextChange = sp.to;
+              spanEndStyle = "";
+            }
+            if (m.className) spanStyle += " " + m.className;
+            if (m.css) css = m.css;
+            if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
+            if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
+            if (m.title && !title) title = m.title;
+            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
+              collapsed = sp;
+          } else if (sp.from > pos && nextChange > sp.from) {
+            nextChange = sp.from;
+          }
+        }
+        if (collapsed && (collapsed.from || 0) == pos) {
+          buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
+                             collapsed.marker, collapsed.from == null);
+          if (collapsed.to == null) return;
+          if (collapsed.to == pos) collapsed = false;
+        }
+        if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
+          buildCollapsedSpan(builder, 0, foundBookmarks[j]);
+      }
+      if (pos >= len) break;
+
+      var upto = Math.min(len, nextChange);
+      while (true) {
+        if (text) {
+          var end = pos + text.length;
+          if (!collapsed) {
+            var tokenText = end > upto ? text.slice(0, upto - pos) : text;
+            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
+                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
+          }
+          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
+          pos = end;
+          spanStartStyle = "";
+        }
+        text = allText.slice(at, at = styles[i++]);
+        style = interpretTokenStyle(styles[i++], builder.cm.options);
+      }
+    }
+  }
+
+  // DOCUMENT DATA STRUCTURE
+
+  // By default, updates that start and end at the beginning of a line
+  // are treated specially, in order to make the association of line
+  // widgets and marker elements with the text behave more intuitive.
+  function isWholeLineUpdate(doc, change) {
+    return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
+      (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
+  }
+
+  // Perform a change on the document data structure.
+  function updateDoc(doc, change, markedSpans, estimateHeight) {
+    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
+    function update(line, text, spans) {
+      updateLine(line, text, spans, estimateHeight);
+      signalLater(line, "change", line, change);
+    }
+    function linesFor(start, end) {
+      for (var i = start, result = []; i < end; ++i)
+        result.push(new Line(text[i], spansFor(i), estimateHeight));
+      return result;
+    }
+
+    var from = change.from, to = change.to, text = change.text;
+    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
+    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
+
+    // Adjust the line structure
+    if (change.full) {
+      doc.insert(0, linesFor(0, text.length));
+      doc.remove(text.length, doc.size - text.length);
+    } else if (isWholeLineUpdate(doc, change)) {
+      // This is a whole-line replace. Treated specially to make
+      // sure line objects move the way they are supposed to.
+      var added = linesFor(0, text.length - 1);
+      update(lastLine, lastLine.text, lastSpans);
+      if (nlines) doc.remove(from.line, nlines);
+      if (added.length) doc.insert(from.line, added);
+    } else if (firstLine == lastLine) {
+      if (text.length == 1) {
+        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
+      } else {
+        var added = linesFor(1, text.length - 1);
+        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
+        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+        doc.insert(from.line + 1, added);
+      }
+    } else if (text.length == 1) {
+      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
+      doc.remove(from.line + 1, nlines);
+    } else {
+      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
+      var added = linesFor(1, text.length - 1);
+      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
+      doc.insert(from.line + 1, added);
+    }
+
+    signalLater(doc, "change", doc, change);
+  }
+
+  // The document is represented as a BTree consisting of leaves, with
+  // chunk of lines in them, and branches, with up to ten leaves or
+  // other branch nodes below them. The top node is always a branch
+  // node, and is the document object itself (meaning it has
+  // additional methods and properties).
+  //
+  // All nodes have parent links. The tree is used both to go from
+  // line numbers to line objects, and to go from objects to numbers.
+  // It also indexes by height, and is used to convert between height
+  // and line object, and to find the total height of the document.
+  //
+  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
+
+  function LeafChunk(lines) {
+    this.lines = lines;
+    this.parent = null;
+    for (var i = 0, height = 0; i < lines.length; ++i) {
+      lines[i].parent = this;
+      height += lines[i].height;
+    }
+    this.height = height;
+  }
+
+  LeafChunk.prototype = {
+    chunkSize: function() { return this.lines.length; },
+    // Remove the n lines at offset 'at'.
+    removeInner: function(at, n) {
+      for (var i = at, e = at + n; i < e; ++i) {
+        var line = this.lines[i];
+        this.height -= line.height;
+        cleanUpLine(line);
+        signalLater(line, "delete");
+      }
+      this.lines.splice(at, n);
+    },
+    // Helper used to collapse a small branch into a single leaf.
+    collapse: function(lines) {
+      lines.push.apply(lines, this.lines);
+    },
+    // Insert the given array of lines at offset 'at', count them as
+    // having the given height.
+    insertInner: function(at, lines, height) {
+      this.height += height;
+      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+      for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
+    },
+    // Used to iterate over a part of the tree.
+    iterN: function(at, n, op) {
+      for (var e = at + n; at < e; ++at)
+        if (op(this.lines[at])) return true;
+    }
+  };
+
+  function BranchChunk(children) {
+    this.children = children;
+    var size = 0, height = 0;
+    for (var i = 0; i < children.length; ++i) {
+      var ch = children[i];
+      size += ch.chunkSize(); height += ch.height;
+      ch.parent = this;
+    }
+    this.size = size;
+    this.height = height;
+    this.parent = null;
+  }
+
+  BranchChunk.prototype = {
+    chunkSize: function() { return this.size; },
+    removeInner: function(at, n) {
+      this.size -= n;
+      for (var i = 0; i < this.children.length; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at < sz) {
+          var rm = Math.min(n, sz - at), oldHeight = child.height;
+          child.removeInner(at, rm);
+          this.height -= oldHeight - child.height;
+          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+          if ((n -= rm) == 0) break;
+          at = 0;
+        } else at -= sz;
+      }
+      // If the result is smaller than 25 lines, ensure that it is a
+      // single leaf node.
+      if (this.size - n < 25 &&
+          (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
+        var lines = [];
+        this.collapse(lines);
+        this.children = [new LeafChunk(lines)];
+        this.children[0].parent = this;
+      }
+    },
+    collapse: function(lines) {
+      for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
+    },
+    insertInner: function(at, lines, height) {
+      this.size += lines.length;
+      this.height += height;
+      for (var i = 0; i < this.children.length; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at <= sz) {
+          child.insertInner(at, lines, height);
+          if (child.lines && child.lines.length > 50) {
+            while (child.lines.length > 50) {
+              var spilled = child.lines.splice(child.lines.length - 25, 25);
+              var newleaf = new LeafChunk(spilled);
+              child.height -= newleaf.height;
+              this.children.splice(i + 1, 0, newleaf);
+              newleaf.parent = this;
+            }
+            this.maybeSpill();
+          }
+          break;
+        }
+        at -= sz;
+      }
+    },
+    // When a node has grown, check whether it should be split.
+    maybeSpill: function() {
+      if (this.children.length <= 10) return;
+      var me = this;
+      do {
+        var spilled = me.children.splice(me.children.length - 5, 5);
+        var sibling = new BranchChunk(spilled);
+        if (!me.parent) { // Become the parent node
+          var copy = new BranchChunk(me.children);
+          copy.parent = me;
+          me.children = [copy, sibling];
+          me = copy;
+        } else {
+          me.size -= sibling.size;
+          me.height -= sibling.height;
+          var myIndex = indexOf(me.parent.children, me);
+          me.parent.children.splice(myIndex + 1, 0, sibling);
+        }
+        sibling.parent = me.parent;
+      } while (me.children.length > 10);
+      me.parent.maybeSpill();
+    },
+    iterN: function(at, n, op) {
+      for (var i = 0; i < this.children.length; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at < sz) {
+          var used = Math.min(n, sz - at);
+          if (child.iterN(at, used, op)) return true;
+          if ((n -= used) == 0) break;
+          at = 0;
+        } else at -= sz;
+      }
+    }
+  };
+
+  var nextDocId = 0;
+  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
+    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
+    if (firstLine == null) firstLine = 0;
+
+    BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
+    this.first = firstLine;
+    this.scrollTop = this.scrollLeft = 0;
+    this.cantEdit = false;
+    this.cleanGeneration = 1;
+    this.frontier = firstLine;
+    var start = Pos(firstLine, 0);
+    this.sel = simpleSelection(start);
+    this.history = new History(null);
+    this.id = ++nextDocId;
+    this.modeOption = mode;
+
+    if (typeof text == "string") text = splitLines(text);
+    updateDoc(this, {from: start, to: start, text: text});
+    setSelection(this, simpleSelection(start), sel_dontScroll);
+  };
+
+  Doc.prototype = createObj(BranchChunk.prototype, {
+    constructor: Doc,
+    // Iterate over the document. Supports two forms -- with only one
+    // argument, it calls that for each line in the document. With
+    // three, it iterates over the range given by the first two (with
+    // the second being non-inclusive).
+    iter: function(from, to, op) {
+      if (op) this.iterN(from - this.first, to - from, op);
+      else this.iterN(this.first, this.first + this.size, from);
+    },
+
+    // Non-public interface for adding and removing lines.
+    insert: function(at, lines) {
+      var height = 0;
+      for (var i = 0; i < lines.length; ++i) height += lines[i].height;
+      this.insertInner(at - this.first, lines, height);
+    },
+    remove: function(at, n) { this.removeInner(at - this.first, n); },
+
+    // From here, the methods are part of the public interface. Most
+    // are also available from CodeMirror (editor) instances.
+
+    getValue: function(lineSep, lineFilter) {
+      var lines = getLines(this, this.first, this.first + this.size, lineFilter);
+      if (lineSep === false) return lines;
+      return lines.join(lineSep || "\n");
+    },
+    setValue: docMethodOp(function(code) {
+      var top = Pos(this.first, 0), last = this.first + this.size - 1;
+      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
+                        text: splitLines(code), origin: "setValue", full: true}, true);
+      setSelection(this, simpleSelection(top));
+    }),
+    replaceRange: function(code, from, to, origin) {
+      from = clipPos(this, from);
+      to = to ? clipPos(this, to) : from;
+      replaceRange(this, code, from, to, origin);
+    },
+    getRange: function(from, to, lineSep) {
+      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
+      if (lineSep === false) return lines;
+      return lines.join(lineSep || "\n");
+    },
+
+    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
+
+    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
+    getLineNumber: function(line) {return lineNo(line);},
+
+    getLineHandleVisualStart: function(line) {
+      if (typeof line == "number") line = getLine(this, line);
+      return visualLine(line);
+    },
+
+    lineCount: function() {return this.size;},
+    firstLine: function() {return this.first;},
+    lastLine: function() {return this.first + this.size - 1;},
+
+    clipPos: function(pos) {return clipPos(this, pos);},
+
+    getCursor: function(start) {
+      var range = this.sel.primary(), pos;
+      if (start == null || start == "head") pos = range.head;
+      else if (start == "anchor") pos = range.anchor;
+      else if (start == "end" || start == "to" || start === false) pos = range.to();
+      else pos = range.from();
+      return pos;
+    },
+    listSelections: function() { return this.sel.ranges; },
+    somethingSelected: function() {return this.sel.somethingSelected();},
+
+    setCursor: docMethodOp(function(line, ch, options) {
+      setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
+    }),
+    setSelection: docMethodOp(function(anchor, head, options) {
+      setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
+    }),
+    extendSelection: docMethodOp(function(head, other, options) {
+      extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
+    }),
+    extendSelections: docMethodOp(function(heads, options) {
+      extendSelections(this, clipPosArray(this, heads, options));
+    }),
+    extendSelectionsBy: docMethodOp(function(f, options) {
+      extendSelections(this, map(this.sel.ranges, f), options);
+    }),
+    setSelections: docMethodOp(function(ranges, primary, options) {
+      if (!ranges.length) return;
+      for (var i = 0, out = []; i < ranges.length; i++)
+        out[i] = new Range(clipPos(this, ranges[i].anchor),
+                           clipPos(this, ranges[i].head));
+      if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
+      setSelection(this, normalizeSelection(out, primary), options);
+    }),
+    addSelection: docMethodOp(function(anchor, head, options) {
+      var ranges = this.sel.ranges.slice(0);
+      ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
+      setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
+    }),
+
+    getSelection: function(lineSep) {
+      var ranges = this.sel.ranges, lines;
+      for (var i = 0; i < ranges.length; i++) {
+        var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+        lines = lines ? lines.concat(sel) : sel;
+      }
+      if (lineSep === false) return lines;
+      else return lines.join(lineSep || "\n");
+    },
+    getSelections: function(lineSep) {
+      var parts = [], ranges = this.sel.ranges;
+      for (var i = 0; i < ranges.length; i++) {
+        var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+        if (lineSep !== false) sel = sel.join(lineSep || "\n");
+        parts[i] = sel;
+      }
+      return parts;
+    },
+    replaceSelection: function(code, collapse, origin) {
+      var dup = [];
+      for (var i = 0; i < this.sel.ranges.length; i++)
+        dup[i] = code;
+      this.replaceSelections(dup, collapse, origin || "+input");
+    },
+    replaceSelections: docMethodOp(function(code, collapse, origin) {
+      var changes = [], sel = this.sel;
+      for (var i = 0; i < sel.ranges.length; i++) {
+        var range = sel.ranges[i];
+        changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
+      }
+      var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
+      for (var i = changes.length - 1; i >= 0; i--)
+        makeChange(this, changes[i]);
+      if (newSel) setSelectionReplaceHistory(this, newSel);
+      else if (this.cm) ensureCursorVisible(this.cm);
+    }),
+    undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
+    redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
+    undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
+    redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
+
+    setExtending: function(val) {this.extend = val;},
+    getExtending: function() {return this.extend;},
+
+    historySize: function() {
+      var hist = this.history, done = 0, undone = 0;
+      for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
+      for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
+      return {undo: done, redo: undone};
+    },
+    clearHistory: function() {this.history = new History(this.history.maxGeneration);},
+
+    markClean: function() {
+      this.cleanGeneration = this.changeGeneration(true);
+    },
+    changeGeneration: function(forceSplit) {
+      if (forceSplit)
+        this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
+      return this.history.generation;
+    },
+    isClean: function (gen) {
+      return this.history.generation == (gen || this.cleanGeneration);
+    },
+
+    getHistory: function() {
+      return {done: copyHistoryArray(this.history.done),
+              undone: copyHistoryArray(this.history.undone)};
+    },
+    setHistory: function(histData) {
+      var hist = this.history = new History(this.history.maxGeneration);
+      hist.done = copyHistoryArray(histData.done.slice(0), null, true);
+      hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
+    },
+
+    addLineClass: docMethodOp(function(handle, where, cls) {
+      return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
+        var prop = where == "text" ? "textClass"
+                 : where == "background" ? "bgClass"
+                 : where == "gutter" ? "gutterClass" : "wrapClass";
+        if (!line[prop]) line[prop] = cls;
+        else if (classTest(cls).test(line[prop])) return false;
+        else line[prop] += " " + cls;
+        return true;
+      });
+    }),
+    removeLineClass: docMethodOp(function(handle, where, cls) {
+      return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
+        var prop = where == "text" ? "textClass"
+                 : where == "background" ? "bgClass"
+                 : where == "gutter" ? "gutterClass" : "wrapClass";
+        var cur = line[prop];
+        if (!cur) return false;
+        else if (cls == null) line[prop] = null;
+        else {
+          var found = cur.match(classTest(cls));
+          if (!found) return false;
+          var end = found.index + found[0].length;
+          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
+        }
+        return true;
+      });
+    }),
+
+    addLineWidget: docMethodOp(function(handle, node, options) {
+      return addLineWidget(this, handle, node, options);
+    }),
+    removeLineWidget: function(widget) { widget.clear(); },
+
+    markText: function(from, to, options) {
+      return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
+    },
+    setBookmark: function(pos, options) {
+      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
+                      insertLeft: options && options.insertLeft,
+                      clearWhenEmpty: false, shared: options && options.shared,
+                      handleMouseEvents: options && options.handleMouseEvents};
+      pos = clipPos(this, pos);
+      return markText(this, pos, pos, realOpts, "bookmark");
+    },
+    findMarksAt: function(pos) {
+      pos = clipPos(this, pos);
+      var markers = [], spans = getLine(this, pos.line).markedSpans;
+      if (spans) for (var i = 0; i < spans.length; ++i) {
+        var span = spans[i];
+        if ((span.from == null || span.from <= pos.ch) &&
+            (span.to == null || span.to >= pos.ch))
+          markers.push(span.marker.parent || span.marker);
+      }
+      return markers;
+    },
+    findMarks: function(from, to, filter) {
+      from = clipPos(this, from); to = clipPos(this, to);
+      var found = [], lineNo = from.line;
+      this.iter(from.line, to.line + 1, function(line) {
+        var spans = line.markedSpans;
+        if (spans) for (var i = 0; i < spans.length; i++) {
+          var span = spans[i];
+          if (!(lineNo == from.line && from.ch > span.to ||
+                span.from == null && lineNo != from.line||
+                lineNo == to.line && span.from > to.ch) &&
+              (!filter || filter(span.marker)))
+            found.push(span.marker.parent || span.marker);
+        }
+        ++lineNo;
+      });
+      return found;
+    },
+    getAllMarks: function() {
+      var markers = [];
+      this.iter(function(line) {
+        var sps = line.markedSpans;
+        if (sps) for (var i = 0; i < sps.length; ++i)
+          if (sps[i].from != null) markers.push(sps[i].marker);
+      });
+      return markers;
+    },
+
+    posFromIndex: function(off) {
+      var ch, lineNo = this.first;
+      this.iter(function(line) {
+        var sz = line.text.length + 1;
+        if (sz > off) { ch = off; return true; }
+        off -= sz;
+        ++lineNo;
+      });
+      return clipPos(this, Pos(lineNo, ch));
+    },
+    indexFromPos: function (coords) {
+      coords = clipPos(this, coords);
+      var index = coords.ch;
+      if (coords.line < this.first || coords.ch < 0) return 0;
+      this.iter(this.first, coords.line, function (line) {
+        index += line.text.length + 1;
+      });
+      return index;
+    },
+
+    copy: function(copyHistory) {
+      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
+      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
+      doc.sel = this.sel;
+      doc.extend = false;
+      if (copyHistory) {
+        doc.history.undoDepth = this.history.undoDepth;
+        doc.setHistory(this.getHistory());
+      }
+      return doc;
+    },
+
+    linkedDoc: function(options) {
+      if (!options) options = {};
+      var from = this.first, to = this.first + this.size;
+      if (options.from != null && options.from > from) from = options.from;
+      if (options.to != null && options.to < to) to = options.to;
+      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
+      if (options.sharedHist) copy.history = this.history;
+      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
+      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
+      copySharedMarkers(copy, findSharedMarkers(this));
+      return copy;
+    },
+    unlinkDoc: function(other) {
+      if (other instanceof CodeMirror) other = other.doc;
+      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
+        var link = this.linked[i];
+        if (link.doc != other) continue;
+        this.linked.splice(i, 1);
+        other.unlinkDoc(this);
+        detachSharedMarkers(findSharedMarkers(this));
+        break;
+      }
+      // If the histories were shared, split them again
+      if (other.history == this.history) {
+        var splitIds = [other.id];
+        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
+        other.history = new History(null);
+        other.history.done = copyHistoryArray(this.history.done, splitIds);
+        other.history.undone = copyHistoryArray(this.history.undone, splitIds);
+      }
+    },
+    iterLinkedDocs: function(f) {linkedDocs(this, f);},
+
+    getMode: function() {return this.mode;},
+    getEditor: function() {return this.cm;}
+  });
+
+  // Public alias.
+  Doc.prototype.eachLine = Doc.prototype.iter;
+
+  // Set up methods on CodeMirror's prototype to redirect to the editor's document.
+  var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
+  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
+    CodeMirror.prototype[prop] = (function(method) {
+      return function() {return method.apply(this.doc, arguments);};
+    })(Doc.prototype[prop]);
+
+  eventMixin(Doc);
+
+  // Call f for all linked documents.
+  function linkedDocs(doc, f, sharedHistOnly) {
+    function propagate(doc, skip, sharedHist) {
+      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
+        var rel = doc.linked[i];
+        if (rel.doc == skip) continue;
+        var shared = sharedHist && rel.sharedHist;
+        if (sharedHistOnly && !shared) continue;
+        f(rel.doc, shared);
+        propagate(rel.doc, doc, shared);
+      }
+    }
+    propagate(doc, null, true);
+  }
+
+  // Attach a document to an editor.
+  function attachDoc(cm, doc) {
+    if (doc.cm) throw new Error("This document is already in use.");
+    cm.doc = doc;
+    doc.cm = cm;
+    estimateLineHeights(cm);
+    loadMode(cm);
+    if (!cm.options.lineWrapping) findMaxLine(cm);
+    cm.options.mode = doc.modeOption;
+    regChange(cm);
+  }
+
+  // LINE UTILITIES
+
+  // Find the line object corresponding to the given line number.
+  function getLine(doc, n) {
+    n -= doc.first;
+    if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
+    for (var chunk = doc; !chunk.lines;) {
+      for (var i = 0;; ++i) {
+        var child = chunk.children[i], sz = child.chunkSize();
+        if (n < sz) { chunk = child; break; }
+        n -= sz;
+      }
+    }
+    return chunk.lines[n];
+  }
+
+  // Get the part of a document between two positions, as an array of
+  // strings.
+  function getBetween(doc, start, end) {
+    var out = [], n = start.line;
+    doc.iter(start.line, end.line + 1, function(line) {
+      var text = line.text;
+      if (n == end.line) text = text.slice(0, end.ch);
+      if (n == start.line) text = text.slice(start.ch);
+      out.push(text);
+      ++n;
+    });
+    return out;
+  }
+  // Get the lines between from and to, as array of strings.
+  function getLines(doc, from, to, lineFilter) {
+    var out = [];
+    doc.iter(from, to, function(line) {
+      var text = line.text;
+      if(lineFilter){
+        text = lineFilter(line);
+      }
+      out.push(text);
+    });
+    return out;
+  }
+
+  // Update the height of a line, propagating the height change
+  // upwards to parent nodes.
+  function updateLineHeight(line, height) {
+    var diff = height - line.height;
+    if (diff) for (var n = line; n; n = n.parent) n.height += diff;
+  }
+
+  // Given a line object, find its line number by walking up through
+  // its parent links.
+  function lineNo(line) {
+    if (line.parent == null) return null;
+    var cur = line.parent, no = indexOf(cur.lines, line);
+    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+      for (var i = 0;; ++i) {
+        if (chunk.children[i] == cur) break;
+        no += chunk.children[i].chunkSize();
+      }
+    }
+    return no + cur.first;
+  }
+
+  // Find the line at the given vertical position, using the height
+  // information in the document tree.
+  function lineAtHeight(chunk, h) {
+    var n = chunk.first;
+    outer: do {
+      for (var i = 0; i < chunk.children.length; ++i) {
+        var child = chunk.children[i], ch = child.height;
+        if (h < ch) { chunk = child; continue outer; }
+        h -= ch;
+        n += child.chunkSize();
+      }
+      return n;
+    } while (!chunk.lines);
+    for (var i = 0; i < chunk.lines.length; ++i) {
+      var line = chunk.lines[i], lh = line.height;
+      if (h < lh) break;
+      h -= lh;
+    }
+    return n + i;
+  }
+
+
+  // Find the height above the given line.
+  function heightAtLine(lineObj) {
+    lineObj = visualLine(lineObj);
+
+    var h = 0, chunk = lineObj.parent;
+    for (var i = 0; i < chunk.lines.length; ++i) {
+      var line = chunk.lines[i];
+      if (line == lineObj) break;
+      else h += line.height;
+    }
+    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
+      for (var i = 0; i < p.children.length; ++i) {
+        var cur = p.children[i];
+        if (cur == chunk) break;
+        else h += cur.height;
+      }
+    }
+    return h;
+  }
+
+  // Get the bidi ordering for the given line (and cache it). Returns
+  // false for lines that are fully left-to-right, and an array of
+  // BidiSpan objects otherwise.
+  function getOrder(line) {
+    var order = line.order;
+    if (order == null) order = line.order = bidiOrdering(line.text);
+    return order;
+  }
+
+  // HISTORY
+
+  function History(startGen) {
+    // Arrays of change events and selections. Doing something adds an
+    // event to done and clears undo. Undoing moves events from done
+    // to undone, redoing moves them in the other direction.
+    this.done = []; this.undone = [];
+    this.undoDepth = Infinity;
+    // Used to track when changes can be merged into a single undo
+    // event
+    this.lastModTime = this.lastSelTime = 0;
+    this.lastOp = this.lastSelOp = null;
+    this.lastOrigin = this.lastSelOrigin = null;
+    // Used by the isClean() method
+    this.generation = this.maxGeneration = startGen || 1;
+  }
+
+  // Create a history change event from an updateDoc-style change
+  // object.
+  function historyChangeFromChange(doc, change) {
+    var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
+    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
+    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
+    return histChange;
+  }
+
+  // Pop all selection events off the end of a history array. Stop at
+  // a change event.
+  function clearSelectionEvents(array) {
+    while (array.length) {
+      var last = lst(array);
+      if (last.ranges) array.pop();
+      else break;
+    }
+  }
+
+  // Find the top change event in the history. Pop off selection
+  // events that are in the way.
+  function lastChangeEvent(hist, force) {
+    if (force) {
+      clearSelectionEvents(hist.done);
+      return lst(hist.done);
+    } else if (hist.done.length && !lst(hist.done).ranges) {
+      return lst(hist.done);
+    } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
+      hist.done.pop();
+      return lst(hist.done);
+    }
+  }
+
+  // Register a change in the history. Merges changes that are within
+  // a single operation, ore are close together with an origin that
+  // allows merging (starting with "+") into a single event.
+  function addChangeToHistory(doc, change, selAfter, opId) {
+    var hist = doc.history;
+    hist.undone.length = 0;
+    var time = +new Date, cur;
+
+    if ((hist.lastOp == opId ||
+         hist.lastOrigin == change.origin && change.origin &&
+         ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
+          change.origin.charAt(0) == "*")) &&
+        (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
+      // Merge this change into the last event
+      var last = lst(cur.changes);
+      if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
+        // Optimized case for simple insertion -- don't want to add
+        // new changesets for every character typed
+        last.to = changeEnd(change);
+      } else {
+        // Add new sub-event
+        cur.changes.push(historyChangeFromChange(doc, change));
+      }
+    } else {
+      // Can not be merged, start a new event.
+      var before = lst(hist.done);
+      if (!before || !before.ranges)
+        pushSelectionToHistory(doc.sel, hist.done);
+      cur = {changes: [historyChangeFromChange(doc, change)],
+             generation: hist.generation};
+      hist.done.push(cur);
+      while (hist.done.length > hist.undoDepth) {
+        hist.done.shift();
+        if (!hist.done[0].ranges) hist.done.shift();
+      }
+    }
+    hist.done.push(selAfter);
+    hist.generation = ++hist.maxGeneration;
+    hist.lastModTime = hist.lastSelTime = time;
+    hist.lastOp = hist.lastSelOp = opId;
+    hist.lastOrigin = hist.lastSelOrigin = change.origin;
+
+    if (!last) signal(doc, "historyAdded");
+  }
+
+  function selectionEventCanBeMerged(doc, origin, prev, sel) {
+    var ch = origin.charAt(0);
+    return ch == "*" ||
+      ch == "+" &&
+      prev.ranges.length == sel.ranges.length &&
+      prev.somethingSelected() == sel.somethingSelected() &&
+      new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
+  }
+
+  // Called whenever the selection changes, sets the new selection as
+  // the pending selection in the history, and pushes the old pending
+  // selection into the 'done' array when it was significantly
+  // different (in number of selected ranges, emptiness, or time).
+  function addSelectionToHistory(doc, sel, opId, options) {
+    var hist = doc.history, origin = options && options.origin;
+
+    // A new event is started when the previous origin does not match
+    // the current, or the origins don't allow matching. Origins
+    // starting with * are always merged, those starting with + are
+    // merged when similar and close together in time.
+    if (opId == hist.lastSelOp ||
+        (origin && hist.lastSelOrigin == origin &&
+         (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
+          selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
+      hist.done[hist.done.length - 1] = sel;
+    else
+      pushSelectionToHistory(sel, hist.done);
+
+    hist.lastSelTime = +new Date;
+    hist.lastSelOrigin = origin;
+    hist.lastSelOp = opId;
+    if (options && options.clearRedo !== false)
+      clearSelectionEvents(hist.undone);
+  }
+
+  function pushSelectionToHistory(sel, dest) {
+    var top = lst(dest);
+    if (!(top && top.ranges && top.equals(sel)))
+      dest.push(sel);
+  }
+
+  // Used to store marked span information in the history.
+  function attachLocalSpans(doc, change, from, to) {
+    var existing = change["spans_" + doc.id], n = 0;
+    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
+      if (line.markedSpans)
+        (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
+      ++n;
+    });
+  }
+
+  // When un/re-doing restores text containing marked spans, those
+  // that have been explicitly cleared should not be restored.
+  function removeClearedSpans(spans) {
+    if (!spans) return null;
+    for (var i = 0, out; i < spans.length; ++i) {
+      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
+      else if (out) out.push(spans[i]);
+    }
+    return !out ? spans : out.length ? out : null;
+  }
+
+  // Retrieve and filter the old marked spans stored in a change event.
+  function getOldSpans(doc, change) {
+    var found = change["spans_" + doc.id];
+    if (!found) return null;
+    for (var i = 0, nw = []; i < change.text.length; ++i)
+      nw.push(removeClearedSpans(found[i]));
+    return nw;
+  }
+
+  // Used both to provide a JSON-safe object in .getHistory, and, when
+  // detaching a document, to split the history in two
+  function copyHistoryArray(events, newGroup, instantiateSel) {
+    for (var i = 0, copy = []; i < events.length; ++i) {
+      var event = events[i];
+      if (event.ranges) {
+        copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
+        continue;
+      }
+      var changes = event.changes, newChanges = [];
+      copy.push({changes: newChanges});
+      for (var j = 0; j < changes.length; ++j) {
+        var change = changes[j], m;
+        newChanges.push({from: change.from, to: change.to, text: change.text});
+        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
+          if (indexOf(newGroup, Number(m[1])) > -1) {
+            lst(newChanges)[prop] = change[prop];
+            delete change[prop];
+          }
+        }
+      }
+    }
+    return copy;
+  }
+
+  // Rebasing/resetting history to deal with externally-sourced changes
+
+  function rebaseHistSelSingle(pos, from, to, diff) {
+    if (to < pos.line) {
+      pos.line += diff;
+    } else if (from < pos.line) {
+      pos.line = from;
+      pos.ch = 0;
+    }
+  }
+
+  // Tries to rebase an array of history events given a change in the
+  // document. If the change touches the same lines as the event, the
+  // event, and everything 'behind' it, is discarded. If the change is
+  // before the event, the event's positions are updated. Uses a
+  // copy-on-write scheme for the positions, to avoid having to
+  // reallocate them all on every rebase, but also avoid problems with
+  // shared position objects being unsafely updated.
+  function rebaseHistArray(array, from, to, diff) {
+    for (var i = 0; i < array.length; ++i) {
+      var sub = array[i], ok = true;
+      if (sub.ranges) {
+        if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
+        for (var j = 0; j < sub.ranges.length; j++) {
+          rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
+          rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
+        }
+        continue;
+      }
+      for (var j = 0; j < sub.changes.length; ++j) {
+        var cur = sub.changes[j];
+        if (to < cur.from.line) {
+          cur.from = Pos(cur.from.line + diff, cur.from.ch);
+          cur.to = Pos(cur.to.line + diff, cur.to.ch);
+        } else if (from <= cur.to.line) {
+          ok = false;
+          break;
+        }
+      }
+      if (!ok) {
+        array.splice(0, i + 1);
+        i = 0;
+      }
+    }
+  }
+
+  function rebaseHist(hist, change) {
+    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
+    rebaseHistArray(hist.done, from, to, diff);
+    rebaseHistArray(hist.undone, from, to, diff);
+  }
+
+  // EVENT UTILITIES
+
+  // Due to the fact that we still support jurassic IE versions, some
+  // compatibility wrappers are needed.
+
+  var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
+    if (e.preventDefault) e.preventDefault();
+    else e.returnValue = false;
+  };
+  var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
+    if (e.stopPropagation) e.stopPropagation();
+    else e.cancelBubble = true;
+  };
+  function e_defaultPrevented(e) {
+    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
+  }
+  var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
+
+  function e_target(e) {return e.target || e.srcElement;}
+  function e_button(e) {
+    var b = e.which;
+    if (b == null) {
+      if (e.button & 1) b = 1;
+      else if (e.button & 2) b = 3;
+      else if (e.button & 4) b = 2;
+    }
+    if (mac && e.ctrlKey && b == 1) b = 3;
+    return b;
+  }
+
+  // EVENT HANDLING
+
+  // Lightweight event framework. on/off also work on DOM nodes,
+  // registering native DOM handlers.
+
+  var on = CodeMirror.on = function(emitter, type, f) {
+    if (emitter.addEventListener)
+      emitter.addEventListener(type, f, false);
+    else if (emitter.attachEvent)
+      emitter.attachEvent("on" + type, f);
+    else {
+      var map = emitter._handlers || (emitter._handlers = {});
+      var arr = map[type] || (map[type] = []);
+      arr.push(f);
+    }
+  };
+
+  var off = CodeMirror.off = function(emitter, type, f) {
+    if (emitter.removeEventListener)
+      emitter.removeEventListener(type, f, false);
+    else if (emitter.detachEvent)
+      emitter.detachEvent("on" + type, f);
+    else {
+      var arr = emitter._handlers && emitter._handlers[type];
+      if (!arr) return;
+      for (var i = 0; i < arr.length; ++i)
+        if (arr[i] == f) { arr.splice(i, 1); break; }
+    }
+  };
+
+  var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
+    var arr = emitter._handlers && emitter._handlers[type];
+    if (!arr) return;
+    var args = Array.prototype.slice.call(arguments, 2);
+    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+  };
+
+  var orphanDelayedCallbacks = null;
+
+  // Often, we want to signal events at a point where we are in the
+  // middle of some work, but don't want the handler to start calling
+  // other methods on the editor, which might be in an inconsistent
+  // state or simply not expect any other events to happen.
+  // signalLater looks whether there are any handlers, and schedules
+  // them to be executed when the last operation ends, or, if no
+  // operation is active, when a timeout fires.
+  function signalLater(emitter, type /*, values...*/) {
+    var arr = emitter._handlers && emitter._handlers[type];
+    if (!arr) return;
+    var args = Array.prototype.slice.call(arguments, 2), list;
+    if (operationGroup) {
+      list = operationGroup.delayedCallbacks;
+    } else if (orphanDelayedCallbacks) {
+      list = orphanDelayedCallbacks;
+    } else {
+      list = orphanDelayedCallbacks = [];
+      setTimeout(fireOrphanDelayed, 0);
+    }
+    function bnd(f) {return function(){f.apply(null, args);};};
+    for (var i = 0; i < arr.length; ++i)
+      list.push(bnd(arr[i]));
+  }
+
+  function fireOrphanDelayed() {
+    var delayed = orphanDelayedCallbacks;
+    orphanDelayedCallbacks = null;
+    for (var i = 0; i < delayed.length; ++i) delayed[i]();
+  }
+
+  // The DOM events that CodeMirror handles can be overridden by
+  // registering a (non-DOM) handler on the editor for the event name,
+  // and preventDefault-ing the event in that handler.
+  function signalDOMEvent(cm, e, override) {
+    if (typeof e == "string")
+      e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
+    signal(cm, override || e.type, cm, e);
+    return e_defaultPrevented(e) || e.codemirrorIgnore;
+  }
+
+  function signalCursorActivity(cm) {
+    var arr = cm._handlers && cm._handlers.cursorActivity;
+    if (!arr) return;
+    var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
+    for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
+      set.push(arr[i]);
+  }
+
+  function hasHandler(emitter, type) {
+    var arr = emitter._handlers && emitter._handlers[type];
+    return arr && arr.length > 0;
+  }
+
+  // Add on and off methods to a constructor's prototype, to make
+  // registering events on such objects more convenient.
+  function eventMixin(ctor) {
+    ctor.prototype.on = function(type, f) {on(this, type, f);};
+    ctor.prototype.off = function(type, f) {off(this, type, f);};
+  }
+
+  // MISC UTILITIES
+
+  // Number of pixels added to scroller and sizer to hide scrollbar
+  var scrollerGap = 30;
+
+  // Returned or thrown by various protocols to signal 'I'm not
+  // handling this'.
+  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
+
+  // Reused option objects for setSelection & friends
+  var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
+
+  function Delayed() {this.id = null;}
+  Delayed.prototype.set = function(ms, f) {
+    clearTimeout(this.id);
+    this.id = setTimeout(f, ms);
+  };
+
+  // Counts the column offset in a string, taking tabs into account.
+  // Used mostly to find indentation.
+  var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
+    if (end == null) {
+      end = string.search(/[^\s\u00a0]/);
+      if (end == -1) end = string.length;
+    }
+    for (var i = startIndex || 0, n = startValue || 0;;) {
+      var nextTab = string.indexOf("\t", i);
+      if (nextTab < 0 || nextTab >= end)
+        return n + (end - i);
+      n += nextTab - i;
+      n += tabSize - (n % tabSize);
+      i = nextTab + 1;
+    }
+  };
+
+  // The inverse of countColumn -- find the offset that corresponds to
+  // a particular column.
+  function findColumn(string, goal, tabSize) {
+    for (var pos = 0, col = 0;;) {
+      var nextTab = string.indexOf("\t", pos);
+      if (nextTab == -1) nextTab = string.length;
+      var skipped = nextTab - pos;
+      if (nextTab == string.length || col + skipped >= goal)
+        return pos + Math.min(skipped, goal - col);
+      col += nextTab - pos;
+      col += tabSize - (col % tabSize);
+      pos = nextTab + 1;
+      if (col >= goal) return pos;
+    }
+  }
+
+  var spaceStrs = [""];
+  function spaceStr(n) {
+    while (spaceStrs.length <= n)
+      spaceStrs.push(lst(spaceStrs) + " ");
+    return spaceStrs[n];
+  }
+
+  function lst(arr) { return arr[arr.length-1]; }
+
+  var selectInput = function(node) { node.select(); };
+  if (ios) // Mobile Safari apparently has a bug where select() is broken.
+    selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
+  else if (ie) // Suppress mysterious IE10 errors
+    selectInput = function(node) { try { node.select(); } catch(_e) {} };
+
+  function indexOf(array, elt) {
+    for (var i = 0; i < array.length; ++i)
+      if (array[i] == elt) return i;
+    return -1;
+  }
+  function map(array, f) {
+    var out = [];
+    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
+    return out;
+  }
+
+  function nothing() {}
+
+  function createObj(base, props) {
+    var inst;
+    if (Object.create) {
+      inst = Object.create(base);
+    } else {
+      nothing.prototype = base;
+      inst = new nothing();
+    }
+    if (props) copyObj(props, inst);
+    return inst;
+  };
+
+  function copyObj(obj, target, overwrite) {
+    if (!target) target = {};
+    for (var prop in obj)
+      if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+        target[prop] = obj[prop];
+    return target;
+  }
+
+  function bind(f) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    return function(){return f.apply(null, args);};
+  }
+
+  var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
+  var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
+    return /\w/.test(ch) || ch > "\x80" &&
+      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
+  };
+  function isWordChar(ch, helper) {
+    if (!helper) return isWordCharBasic(ch);
+    if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
+    return helper.test(ch);
+  }
+
+  function isEmpty(obj) {
+    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
+    return true;
+  }
+
+  // Extending unicode characters. A series of a non-extending char +
+  // any number of extending chars is treated as a single unit as far
+  // as editing and measuring is concerned. This is not fully correct,
+  // since some scripts/font/browsers also treat other configurations
+  // of code points as a group.
+  var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
+
+  // DOM UTILITIES
+
+  function elt(tag, content, className, style) {
+    var e = document.createElement(tag);
+    if (className) e.className = className;
+    if (style) e.style.cssText = style;
+    if (typeof content == "string") e.appendChild(document.createTextNode(content));
+    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
+    return e;
+  }
+
+  var range;
+  if (document.createRange) range = function(node, start, end, endNode) {
+    var r = document.createRange();
+    r.setEnd(endNode || node, end);
+    r.setStart(node, start);
+    return r;
+  };
+  else range = function(node, start, end) {
+    var r = document.body.createTextRange();
+    try { r.moveToElementText(node.parentNode); }
+    catch(e) { return r; }
+    r.collapse(true);
+    r.moveEnd("character", end);
+    r.moveStart("character", start);
+    return r;
+  };
+
+  function removeChildren(e) {
+    for (var count = e.childNodes.length; count > 0; --count)
+      e.removeChild(e.firstChild);
+    return e;
+  }
+
+  function removeChildrenAndAdd(parent, e) {
+    return removeChildren(parent).appendChild(e);
+  }
+
+  var contains = CodeMirror.contains = function(parent, child) {
+    if (child.nodeType == 3) // Android browser always returns false when child is a textnode
+      child = child.parentNode;
+    if (parent.contains)
+      return parent.contains(child);
+    do {
+      if (child.nodeType == 11) child = child.host;
+      if (child == parent) return true;
+    } while (child = child.parentNode);
+  };
+
+  function activeElt() { return document.activeElement; }
+  // Older versions of IE throws unspecified error when touching
+  // document.activeElement in some cases (during loading, in iframe)
+  if (ie && ie_version < 11) activeElt = function() {
+    try { return document.activeElement; }
+    catch(e) { return document.body; }
+  };
+
+  function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
+  var rmClass = CodeMirror.rmClass = function(node, cls) {
+    var current = node.className;
+    var match = classTest(cls).exec(current);
+    if (match) {
+      var after = current.slice(match.index + match[0].length);
+      node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
+    }
+  };
+  var addClass = CodeMirror.addClass = function(node, cls) {
+    var current = node.className;
+    if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
+  };
+  function joinClasses(a, b) {
+    var as = a.split(" ");
+    for (var i = 0; i < as.length; i++)
+      if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
+    return b;
+  }
+
+  // WINDOW-WIDE EVENTS
+
+  // These must be handled carefully, because naively registering a
+  // handler for each editor will cause the editors to never be
+  // garbage collected.
+
+  function forEachCodeMirror(f) {
+    if (!document.body.getElementsByClassName) return;
+    var byClass = document.body.getElementsByClassName("CodeMirror");
+    for (var i = 0; i < byClass.length; i++) {
+      var cm = byClass[i].CodeMirror;
+      if (cm) f(cm);
+    }
+  }
+
+  var globalsRegistered = false;
+  function ensureGlobalHandlers() {
+    if (globalsRegistered) return;
+    registerGlobalHandlers();
+    globalsRegistered = true;
+  }
+  function registerGlobalHandlers() {
+    // When the window resizes, we need to refresh active editors.
+    var resizeTimer;
+    on(window, "resize", function() {
+      if (resizeTimer == null) resizeTimer = setTimeout(function() {
+        resizeTimer = null;
+        forEachCodeMirror(onResize);
+      }, 100);
+    });
+    // When the window loses focus, we want to show the editor as blurred
+    on(window, "blur", function() {
+      forEachCodeMirror(onBlur);
+    });
+  }
+
+  // FEATURE DETECTION
+
+  // Detect drag-and-drop
+  var dragAndDrop = function() {
+    // There is *some* kind of drag-and-drop support in IE6-8, but I
+    // couldn't get it to work yet.
+    if (ie && ie_version < 9) return false;
+    var div = elt('div');
+    return "draggable" in div || "dragDrop" in div;
+  }();
+
+  var zwspSupported;
+  function zeroWidthElement(measure) {
+    if (zwspSupported == null) {
+      var test = elt("span", "\u200b");
+      removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
+      if (measure.firstChild.offsetHeight != 0)
+        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
+    }
+    var node = zwspSupported ? elt("span", "\u200b") :
+      elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
+    node.setAttribute("cm-text", "");
+    return node;
+  }
+
+  // Feature-detect IE's crummy client rect reporting for bidi text
+  var badBidiRects;
+  function hasBadBidiRects(measure) {
+    if (badBidiRects != null) return badBidiRects;
+    var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
+    var r0 = range(txt, 0, 1).getBoundingClientRect();
+    if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
+    var r1 = range(txt, 1, 2).getBoundingClientRect();
+    return badBidiRects = (r1.right - r0.right < 3);
+  }
+
+  // See if "".split is the broken IE version, if so, provide an
+  // alternative way to split lines.
+  var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+    var pos = 0, result = [], l = string.length;
+    while (pos <= l) {
+      var nl = string.indexOf("\n", pos);
+      if (nl == -1) nl = string.length;
+      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
+      var rt = line.indexOf("\r");
+      if (rt != -1) {
+        result.push(line.slice(0, rt));
+        pos += rt + 1;
+      } else {
+        result.push(line);
+        pos = nl + 1;
+      }
+    }
+    return result;
+  } : function(string){return string.split(/\r\n?|\n/);};
+
+  var hasSelection = window.getSelection ? function(te) {
+    try { return te.selectionStart != te.selectionEnd; }
+    catch(e) { return false; }
+  } : function(te) {
+    try {var range = te.ownerDocument.selection.createRange();}
+    catch(e) {}
+    if (!range || range.parentElement() != te) return false;
+    return range.compareEndPoints("StartToEnd", range) != 0;
+  };
+
+  var hasCopyEvent = (function() {
+    var e = elt("div");
+    if ("oncopy" in e) return true;
+    e.setAttribute("oncopy", "return;");
+    return typeof e.oncopy == "function";
+  })();
+
+  var badZoomedRects = null;
+  function hasBadZoomedRects(measure) {
+    if (badZoomedRects != null) return badZoomedRects;
+    var node = removeChildrenAndAdd(measure, elt("span", "x"));
+    var normal = node.getBoundingClientRect();
+    var fromRange = range(node, 0, 1).getBoundingClientRect();
+    return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
+  }
+
+  // KEY NAMES
+
+  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+                  46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
+                  173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+                  221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+                  63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
+  CodeMirror.keyNames = keyNames;
+  (function() {
+    // Number keys
+    for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
+    // Alphabetic keys
+    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
+    // Function keys
+    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
+  })();
+
+  // BIDI HELPERS
+
+  function iterateBidiSections(order, from, to, f) {
+    if (!order) return f(from, to, "ltr");
+    var found = false;
+    for (var i = 0; i < order.length; ++i) {
+      var part = order[i];
+      if (part.from < to && part.to > from || from == to && part.to == from) {
+        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
+        found = true;
+      }
+    }
+    if (!found) f(from, to, "ltr");
+  }
+
+  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
+  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
+
+  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
+  function lineRight(line) {
+    var order = getOrder(line);
+    if (!order) return line.text.length;
+    return bidiRight(lst(order));
+  }
+
+  function lineStart(cm, lineN) {
+    var line = getLine(cm.doc, lineN);
+    var visual = visualLine(line);
+    if (visual != line) lineN = lineNo(visual);
+    var order = getOrder(visual);
+    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
+    return Pos(lineN, ch);
+  }
+  function lineEnd(cm, lineN) {
+    var merged, line = getLine(cm.doc, lineN);
+    while (merged = collapsedSpanAtEnd(line)) {
+      line = merged.find(1, true).line;
+      lineN = null;
+    }
+    var order = getOrder(line);
+    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
+    return Pos(lineN == null ? lineNo(line) : lineN, ch);
+  }
+  function lineStartSmart(cm, pos) {
+    var start = lineStart(cm, pos.line);
+    var line = getLine(cm.doc, start.line);
+    var order = getOrder(line);
+    if (!order || order[0].level == 0) {
+      var firstNonWS = Math.max(0, line.text.search(/\S/));
+      var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
+      return Pos(start.line, inWS ? 0 : firstNonWS);
+    }
+    return start;
+  }
+
+  function compareBidiLevel(order, a, b) {
+    var linedir = order[0].level;
+    if (a == linedir) return true;
+    if (b == linedir) return false;
+    return a < b;
+  }
+  var bidiOther;
+  function getBidiPartAt(order, pos) {
+    bidiOther = null;
+    for (var i = 0, found; i < order.length; ++i) {
+      var cur = order[i];
+      if (cur.from < pos && cur.to > pos) return i;
+      if ((cur.from == pos || cur.to == pos)) {
+        if (found == null) {
+          found = i;
+        } else if (compareBidiLevel(order, cur.level, order[found].level)) {
+          if (cur.from != cur.to) bidiOther = found;
+          return i;
+        } else {
+          if (cur.from != cur.to) bidiOther = i;
+          return found;
+        }
+      }
+    }
+    return found;
+  }
+
+  function moveInLine(line, pos, dir, byUnit) {
+    if (!byUnit) return pos + dir;
+    do pos += dir;
+    while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
+    return pos;
+  }
+
+  // This is needed in order to move 'visually' through bi-directional
+  // text -- i.e., pressing left should make the cursor go left, even
+  // when in RTL text. The tricky part is the 'jumps', where RTL and
+  // LTR text touch each other. This often requires the cursor offset
+  // to move more than one unit, in order to visually move one unit.
+  function moveVisually(line, start, dir, byUnit) {
+    var bidi = getOrder(line);
+    if (!bidi) return moveLogically(line, start, dir, byUnit);
+    var pos = getBidiPartAt(bidi, start), part = bidi[pos];
+    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
+
+    for (;;) {
+      if (target > part.from && target < part.to) return target;
+      if (target == part.from || target == part.to) {
+        if (getBidiPartAt(bidi, target) == pos) return target;
+        part = bidi[pos += dir];
+        return (dir > 0) == part.level % 2 ? part.to : part.from;
+      } else {
+        part = bidi[pos += dir];
+        if (!part) return null;
+        if ((dir > 0) == part.level % 2)
+          target = moveInLine(line, part.to, -1, byUnit);
+        else
+          target = moveInLine(line, part.from, 1, byUnit);
+      }
+    }
+  }
+
+  function moveLogically(line, start, dir, byUnit) {
+    var target = start + dir;
+    if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
+    return target < 0 || target > line.text.length ? null : target;
+  }
+
+  // Bidirectional ordering algorithm
+  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
+  // that this (partially) implements.
+
+  // One-char codes used for character types:
+  // L (L):   Left-to-Right
+  // R (R):   Right-to-Left
+  // r (AL):  Right-to-Left Arabic
+  // 1 (EN):  European Number
+  // + (ES):  European Number Separator
+  // % (ET):  European Number Terminator
+  // n (AN):  Arabic Number
+  // , (CS):  Common Number Separator
+  // m (NSM): Non-Spacing Mark
+  // b (BN):  Boundary Neutral
+  // s (B):   Paragraph Separator
+  // t (S):   Segment Separator
+  // w (WS):  Whitespace
+  // N (ON):  Other Neutrals
+
+  // Returns null if characters are ordered as they appear
+  // (left-to-right), or an array of sections ({from, to, level}
+  // objects) in the order in which they occur visually.
+  var bidiOrdering = (function() {
+    // Character types for codepoints 0 to 0xff
+    var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
+    // Character types for codepoints 0x600 to 0x6ff
+    var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
+    function charType(code) {
+      if (code <= 0xf7) return lowTypes.charAt(code);
+      else if (0x590 <= code && code <= 0x5f4) return "R";
+      else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
+      else if (0x6ee <= code && code <= 0x8ac) return "r";
+      else if (0x2000 <= code && code <= 0x200b) return "w";
+      else if (code == 0x200c) return "b";
+      else return "L";
+    }
+
+    var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
+    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
+    // Browsers seem to always treat the boundaries of block elements as being L.
+    var outerType = "L";
+
+    function BidiSpan(level, from, to) {
+      this.level = level;
+      this.from = from; this.to = to;
+    }
+
+    return function(str) {
+      if (!bidiRE.test(str)) return false;
+      var len = str.length, types = [];
+      for (var i = 0, type; i < len; ++i)
+        types.push(type = charType(str.charCodeAt(i)));
+
+      // W1. Examine each non-spacing mark (NSM) in the level run, and
+      // change the type of the NSM to the type of the previous
+      // character. If the NSM is at the start of the level run, it will
+      // get the type of sor.
+      for (var i = 0, prev = outerType; i < len; ++i) {
+        var type = types[i];
+        if (type == "m") types[i] = prev;
+        else prev = type;
+      }
+
+      // W2. Search backwards from each instance of a European number
+      // until the first strong type (R, L, AL, or sor) is found. If an
+      // AL is found, change the type of the European number to Arabic
+      // number.
+      // W3. Change all ALs to R.
+      for (var i = 0, cur = outerType; i < len; ++i) {
+        var type = types[i];
+        if (type == "1" && cur == "r") types[i] = "n";
+        else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
+      }
+
+      // W4. A single European separator between two European numbers
+      // changes to a European number. A single common separator between
+      // two numbers of the same type changes to that type.
+      for (var i = 1, prev = types[0]; i < len - 1; ++i) {
+        var type = types[i];
+        if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
+        else if (type == "," && prev == types[i+1] &&
+                 (prev == "1" || prev == "n")) types[i] = prev;
+        prev = type;
+      }
+
+      // W5. A sequence of European terminators adjacent to European
+      // numbers changes to all European numbers.
+      // W6. Otherwise, separators and terminators change to Other
+      // Neutral.
+      for (var i = 0; i < len; ++i) {
+        var type = types[i];
+        if (type == ",") types[i] = "N";
+        else if (type == "%") {
+          for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
+          var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
+          for (var j = i; j < end; ++j) types[j] = replace;
+          i = end - 1;
+        }
+      }
+
+      // W7. Search backwards from each instance of a European number
+      // until the first strong type (R, L, or sor) is found. If an L is
+      // found, then change the type of the European number to L.
+      for (var i = 0, cur = outerType; i < len; ++i) {
+        var type = types[i];
+        if (cur == "L" && type == "1") types[i] = "L";
+        else if (isStrong.test(type)) cur = type;
+      }
+
+      // N1. A sequence of neutrals takes the direction of the
+      // surrounding strong text if the text on both sides has the same
+      // direction. European and Arabic numbers act as if they were R in
+      // terms of their influence on neutrals. Start-of-level-run (sor)
+      // and end-of-level-run (eor) are used at level run boundaries.
+      // N2. Any remaining neutrals take the embedding direction.
+      for (var i = 0; i < len; ++i) {
+        if (isNeutral.test(types[i])) {
+          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
+          var before = (i ? types[i-1] : outerType) == "L";
+          var after = (end < len ? types[end] : outerType) == "L";
+          var replace = before || after ? "L" : "R";
+          for (var j = i; j < end; ++j) types[j] = replace;
+          i = end - 1;
+        }
+      }
+
+      // Here we depart from the documented algorithm, in order to avoid
+      // building up an actual levels array. Since there are only three
+      // levels (0, 1, 2) in an implementation that doesn't take
+      // explicit embedding into account, we can build up the order on
+      // the fly, without following the level-based algorithm.
+      var order = [], m;
+      for (var i = 0; i < len;) {
+        if (countsAsLeft.test(types[i])) {
+          var start = i;
+          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
+          order.push(new BidiSpan(0, start, i));
+        } else {
+          var pos = i, at = order.length;
+          for (++i; i < len && types[i] != "L"; ++i) {}
+          for (var j = pos; j < i;) {
+            if (countsAsNum.test(types[j])) {
+              if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
+              var nstart = j;
+              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
+              order.splice(at, 0, new BidiSpan(2, nstart, j));
+              pos = j;
+            } else ++j;
+          }
+          if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
+        }
+      }
+      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
+        order[0].from = m[0].length;
+        order.unshift(new BidiSpan(0, 0, m[0].length));
+      }
+      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
+        lst(order).to -= m[0].length;
+        order.push(new BidiSpan(0, len - m[0].length, len));
+      }
+      if (order[0].level == 2)
+        order.unshift(new BidiSpan(1, order[0].to, order[0].to));
+      if (order[0].level != lst(order).level)
+        order.push(new BidiSpan(order[0].level, len, len));
+
+      return order;
+    };
+  })();
+
+  // THE END
+
+  CodeMirror.version = "5.4.1";
+
+  return CodeMirror;
+});(function (mod) {
+    mod(CodeMirror);
+})(function (CodeMirror) {
+    var Pos = CodeMirror.Pos;
+
+    function forEach(arr, f) {
+        for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
+    }
+
+    function arrayContains(arr, item) {
+        if (!Array.prototype.indexOf) {
+            var i = arr.length;
+            while (i--) {
+                if (arr[i] === item) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        return arr.indexOf(item) != -1;
+    }
+
+    function scriptHint(editor, keywords, getToken, options) {
+        // Find the token at the cursor
+        var cur = editor.getCursor(), token = getToken(editor, cur);
+        if (/\b(?:string)\b/.test(token.type)) {
+            return;
+        }
+        token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
+
+        if (!/^[\w$_]*$/.test(token.string)) {
+            token = {
+                start: cur.ch, end: cur.ch, string: "", state: token.state,
+                type: token.string == "." ? "property" : null
+            };
+        } else if (token.end > cur.ch) {
+            token.end = cur.ch;
+            token.string = token.string.slice(0, cur.ch - token.start);
+        }
+
+        var tprop = token;
+        // If it is a property, find out what it is a property of.
+        while (tprop.type == "property") {
+            tprop = getToken(editor, Pos(cur.line, tprop.start));
+            if (tprop.string != ".") return;
+            tprop = getToken(editor, Pos(cur.line, tprop.start));
+            if (!context) var context = [];
+            context.push(tprop);
+        }
+        return {
+            list: getCompletions(token, context, keywords, options),
+            from: Pos(cur.line, token.start),
+            to: Pos(cur.line, token.end)
+        };
+    }
+
+    function getFormulaKeywords() {
+        return FormulaCollections;
+    }
+
+    function formulaHint(editor, options) {
+        return scriptHint(editor, getFormulaKeywords(),
+            function (e, cur) {
+                return e.getTokenAt(cur);
+            },
+            options);
+    };
+    CodeMirror.registerHelper("hint", "formula", formulaHint);
+
+    function getCompletions(token, context, keywords, options) {
+        var found = [], start = token.string;
+        if (!start) {
+            return found;
+        }
+        function maybeAdd(str) {
+            if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) {
+                found.push(str);
+            }
+        }
+
+        if (context && context.length) {
+            context.pop();
+        } else {
+            forEach(keywords, maybeAdd);
+        }
+        return found;
+    }
+});(function (mod) {
+    mod(CodeMirror);
+})(function (CodeMirror) {
+    "use strict";
+
+    CodeMirror.defineMode('formula', function () {
+        function wordObj(words) {
+            var o = {};
+            for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;
+            return o;
+        }
+
+        var atoms = wordObj(['false', 'true']);
+        var keywords = wordObj(FormulaCollections);
+
+        function tokenBase(stream, state) {
+            if (stream.eatSpace()) {
+                return null;
+            }
+            var ch = stream.next();
+
+            if (ch === '"' || ch === '\'') {
+                nextUntilUnescaped(stream, ch);
+                return "string";
+            }
+            if (/[\[\],\(\)]/.test(ch)) {
+                return 'bracket';
+            }
+
+            // richie:暂时不需要解析操作符号
+            //if (/[+\-*\/=<>!&|]/.test(ch)) {
+            //  return 'operator';
+            //}
+            //if (/\d|\d./.test(ch)) {
+            //    stream.eatWhile(/\d|\./);
+            //    if (stream.eol() || !/\w/.test(stream.peek())) {
+            //        return 'number';
+            //    }
+            //}
+
+
+
+            stream.eatWhile(/[\w-]/);
+            var word = stream.current();
+            if (atoms.hasOwnProperty(word)) {
+                return "atom";
+            }
+            if (keywords.hasOwnProperty(word)) {
+                return "keyword";
+            }
+            return null;
+        }
+
+        function nextUntilUnescaped(stream, end) {
+            var escaped = false, next;
+            while ((next = stream.next()) != null) {
+                if (next === end && !escaped) {
+                    return false;
+                }
+                escaped = !escaped && next === "\\";
+            }
+            return escaped;
+        }
+
+        function tokenize(stream, state) {
+            return (state.tokens[0] || tokenBase)(stream, state);
+        }
+
+        return {
+            startState: function () {
+                return {tokens: []};
+            },
+            token: function (stream, state) {
+                return tokenize(stream, state);
+            },
+            fold: "brace"
+        };
+    });
+    CodeMirror.defineMIME("text/fx-formula", "formula");
+});// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function (mod) {
+    mod(CodeMirror);
+})(function (CodeMirror) {
+    "use strict";
+
+    var HINT_ELEMENT_CLASS = "CodeMirror-hint";
+    var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
+
+    // This is the old interface, kept around for now to stay
+    // backwards-compatible.
+    CodeMirror.showHint = function (cm, getHints, options) {
+        if (!getHints) return cm.showHint(options);
+        if (options && options.async) getHints.async = true;
+        var newOpts = {hint: getHints};
+        if (options) for (var prop in options) newOpts[prop] = options[prop];
+        return cm.showHint(newOpts);
+    };
+
+    CodeMirror.defineExtension("showHint", function (options) {
+        // We want a single cursor position.
+        if (this.listSelections().length > 1 || this.somethingSelected()) return;
+
+        if (this.state.completionActive) this.state.completionActive.close();
+        var completion = this.state.completionActive = new Completion(this, options);
+        if (!completion.options.hint) return;
+
+        CodeMirror.signal(this, "startCompletion", this);
+        completion.update(true);
+    });
+
+    function Completion(cm, options) {
+        this.cm = cm;
+        this.options = this.buildOptions(options);
+        this.widget = null;
+        this.debounce = 0;
+        this.tick = 0;
+        this.startPos = this.cm.getCursor();
+        this.startLen = this.cm.getLine(this.startPos.line).length;
+
+        var self = this;
+        cm.on("cursorActivity", this.activityFunc = function () {
+            self.cursorActivity();
+        });
+    }
+
+    var requestAnimationFrame = window.requestAnimationFrame || function (fn) {
+            return setTimeout(fn, 1000 / 60);
+        };
+    var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
+
+    Completion.prototype = {
+        close: function () {
+            if (!this.active()) return;
+            this.cm.state.completionActive = null;
+            this.tick = null;
+            this.cm.off("cursorActivity", this.activityFunc);
+
+            if (this.widget && this.data) CodeMirror.signal(this.data, "close");
+            if (this.widget) this.widget.close();
+            CodeMirror.signal(this.cm, "endCompletion", this.cm);
+        },
+
+        active: function () {
+            return this.cm.state.completionActive == this;
+        },
+
+        pick: function (data, i) {
+            var completion = data.list[i];
+            if (completion.hint) completion.hint(this.cm, data, completion);
+            else {
+                this.cm.replaceRange(getText(completion), completion.from || data.from,
+                    completion.to || data.to, "complete");
+                var to = this.cm.getCursor();
+                this.cm.markText(completion.from || data.from, to, {className: "#function", atomic: true});
+                this.cm.replaceSelection("() ");
+                to = this.cm.getCursor();
+                to.ch = to.ch - 2;
+                this.cm.setCursor(to);
+                this.cm.focus();
+            }
+            CodeMirror.signal(data, "pick", completion);
+            this.close();
+        },
+
+        cursorActivity: function () {
+            if (this.debounce) {
+                cancelAnimationFrame(this.debounce);
+                this.debounce = 0;
+            }
+
+            var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
+            if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
+                pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
+                (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
+                this.close();
+            } else {
+                var self = this;
+                this.debounce = requestAnimationFrame(function () {
+                    self.update();
+                });
+                if (this.widget) this.widget.disable();
+            }
+        },
+
+        update: function (first) {
+            if (this.tick == null) return;
+            if (this.data) CodeMirror.signal(this.data, "update");
+            if (!this.options.hint.async) {
+                this.finishUpdate(this.options.hint(this.cm, this.options), first);
+            } else {
+                var myTick = ++this.tick, self = this;
+                this.options.hint(this.cm, function (data) {
+                    if (self.tick == myTick) self.finishUpdate(data, first);
+                }, this.options);
+            }
+        },
+
+        finishUpdate: function (data, first) {
+            this.data = data;
+
+            var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
+            if (this.widget) this.widget.close();
+            if (data && data.list.length) {
+                if (picked && data.list.length == 1) {
+                    this.pick(data, 0);
+                } else {
+                    this.widget = new Widget(this, data);
+                    CodeMirror.signal(data, "shown");
+                }
+            }
+        },
+
+        buildOptions: function (options) {
+            var editor = this.cm.options.hintOptions;
+            var out = {};
+            for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
+            if (editor) for (var prop in editor)
+                if (editor[prop] !== undefined) out[prop] = editor[prop];
+            if (options) for (var prop in options)
+                if (options[prop] !== undefined) out[prop] = options[prop];
+            return out;
+        }
+    };
+
+    function getText(completion) {
+        if (typeof completion == "string") return completion;
+        else return completion.text;
+    }
+
+    function buildKeyMap(completion, handle) {
+        var baseMap = {
+            Up: function () {
+                handle.moveFocus(-1);
+            },
+            Down: function () {
+                handle.moveFocus(1);
+            },
+            PageUp: function () {
+                handle.moveFocus(-handle.menuSize() + 1, true);
+            },
+            PageDown: function () {
+                handle.moveFocus(handle.menuSize() - 1, true);
+            },
+            Home: function () {
+                handle.setFocus(0);
+            },
+            End: function () {
+                handle.setFocus(handle.length - 1);
+            },
+            Enter: handle.pick,
+            Tab: handle.pick,
+            Esc: handle.close
+        };
+        var custom = completion.options.customKeys;
+        var ourMap = custom ? {} : baseMap;
+
+        function addBinding(key, val) {
+            var bound;
+            if (typeof val != "string")
+                bound = function (cm) {
+                    return val(cm, handle);
+                };
+            // This mechanism is deprecated
+            else if (baseMap.hasOwnProperty(val))
+                bound = baseMap[val];
+            else
+                bound = val;
+            ourMap[key] = bound;
+        }
+
+        if (custom)
+            for (var key in custom) if (custom.hasOwnProperty(key))
+                addBinding(key, custom[key]);
+        var extra = completion.options.extraKeys;
+        if (extra)
+            for (var key in extra) if (extra.hasOwnProperty(key))
+                addBinding(key, extra[key]);
+        return ourMap;
+    }
+
+    function getHintElement(hintsElement, el) {
+        while (el && el != hintsElement) {
+            if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
+            el = el.parentNode;
+        }
+    }
+
+    function Widget(completion, data) {
+        this.completion = completion;
+        this.data = data;
+        this.picked = false;
+        var widget = this, cm = completion.cm;
+
+        var hints = this.hints = document.createElement("ul");
+        hints.className = "CodeMirror-hints";
+        this.selectedHint = data.selectedHint || 0;
+
+        var completions = data.list;
+        for (var i = 0; i < completions.length; ++i) {
+            var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
+            var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
+            if (cur.className != null) className = cur.className + " " + className;
+            elt.className = className;
+            if (cur.render) cur.render(elt, data, cur);
+            else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
+            elt.hintId = i;
+        }
+
+        var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
+        var left = pos.left, top = pos.bottom, below = true;
+        hints.style.left = left + "px";
+        hints.style.top = top + "px";
+        // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
+        var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
+        var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
+        (completion.options.container || document.body).appendChild(hints);
+        var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
+        if (overlapY > 0) {
+            var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
+            if (curTop - height > 0) { // Fits above cursor
+                hints.style.top = (top = pos.top - height) + "px";
+                below = false;
+            } else if (height > winH) {
+                hints.style.height = (winH - 5) + "px";
+                hints.style.top = (top = pos.bottom - box.top) + "px";
+                var cursor = cm.getCursor();
+                if (data.from.ch != cursor.ch) {
+                    pos = cm.cursorCoords(cursor);
+                    hints.style.left = (left = pos.left) + "px";
+                    box = hints.getBoundingClientRect();
+                }
+            }
+        }
+        var overlapX = box.right - winW;
+        if (overlapX > 0) {
+            if (box.right - box.left > winW) {
+                hints.style.width = (winW - 5) + "px";
+                overlapX -= (box.right - box.left) - winW;
+            }
+            hints.style.left = (left = pos.left - overlapX) + "px";
+        }
+
+        cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
+            moveFocus: function (n, avoidWrap) {
+                widget.changeActive(widget.selectedHint + n, avoidWrap);
+            },
+            setFocus: function (n) {
+                widget.changeActive(n);
+            },
+            menuSize: function () {
+                return widget.screenAmount();
+            },
+            length: completions.length,
+            close: function () {
+                completion.close();
+            },
+            pick: function () {
+                widget.pick();
+            },
+            data: data
+        }));
+
+        if (completion.options.closeOnUnfocus) {
+            var closingOnBlur;
+            cm.on("blur", this.onBlur = function () {
+                closingOnBlur = setTimeout(function () {
+                    completion.close();
+                }, 100);
+            });
+            cm.on("focus", this.onFocus = function () {
+                clearTimeout(closingOnBlur);
+            });
+        }
+
+        var startScroll = cm.getScrollInfo();
+        cm.on("scroll", this.onScroll = function () {
+            var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
+            var newTop = top + startScroll.top - curScroll.top;
+            var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
+            if (!below) point += hints.offsetHeight;
+            if (point <= editor.top || point >= editor.bottom) return completion.close();
+            hints.style.top = newTop + "px";
+            hints.style.left = (left + startScroll.left - curScroll.left) + "px";
+        });
+
+        CodeMirror.on(hints, "dblclick", function (e) {
+            var t = getHintElement(hints, e.target || e.srcElement);
+            if (t && t.hintId != null) {
+                widget.changeActive(t.hintId);
+                widget.pick();
+            }
+        });
+
+        CodeMirror.on(hints, "click", function (e) {
+            var t = getHintElement(hints, e.target || e.srcElement);
+            if (t && t.hintId != null) {
+                widget.changeActive(t.hintId);
+                if (completion.options.completeOnSingleClick) widget.pick();
+            }
+        });
+
+        CodeMirror.on(hints, "mousedown", function () {
+            setTimeout(function () {
+                cm.focus();
+            }, 20);
+        });
+
+        CodeMirror.signal(data, "select", completions[0], hints.firstChild);
+        return true;
+    }
+
+    Widget.prototype = {
+        close: function () {
+            if (this.completion.widget != this) return;
+            this.completion.widget = null;
+            this.hints.parentNode.removeChild(this.hints);
+            this.completion.cm.removeKeyMap(this.keyMap);
+
+            var cm = this.completion.cm;
+            if (this.completion.options.closeOnUnfocus) {
+                cm.off("blur", this.onBlur);
+                cm.off("focus", this.onFocus);
+            }
+            cm.off("scroll", this.onScroll);
+        },
+
+        disable: function () {
+            this.completion.cm.removeKeyMap(this.keyMap);
+            var widget = this;
+            this.keyMap = {
+                Enter: function () {
+                    widget.picked = true;
+                }
+            };
+            this.completion.cm.addKeyMap(this.keyMap);
+        },
+
+        pick: function () {
+            this.completion.pick(this.data, this.selectedHint);
+        },
+
+        changeActive: function (i, avoidWrap) {
+            if (i >= this.data.list.length)
+                i = avoidWrap ? this.data.list.length - 1 : 0;
+            else if (i < 0)
+                i = avoidWrap ? 0 : this.data.list.length - 1;
+            if (this.selectedHint == i) return;
+            var node = this.hints.childNodes[this.selectedHint];
+            node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
+            node = this.hints.childNodes[this.selectedHint = i];
+            node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
+            if (node.offsetTop < this.hints.scrollTop)
+                this.hints.scrollTop = node.offsetTop - 3;
+            else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
+                this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+            CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
+        },
+
+        screenAmount: function () {
+            return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
+        }
+    };
+
+    CodeMirror.registerHelper("hint", "auto", function (cm, options) {
+        var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
+        if (helpers.length) {
+            for (var i = 0; i < helpers.length; i++) {
+                var cur = helpers[i](cm, options);
+                if (cur && cur.list.length) return cur;
+            }
+        } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
+            if (words) return CodeMirror.hint.fromList(cm, {words: words});
+        } else if (CodeMirror.hint.anyword) {
+            return CodeMirror.hint.anyword(cm, options);
+        }
+    });
+
+    CodeMirror.registerHelper("hint", "fromList", function (cm, options) {
+        var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+        var found = [];
+        for (var i = 0; i < options.words.length; i++) {
+            var word = options.words[i];
+            if (word.slice(0, token.string.length) == token.string)
+                found.push(word);
+        }
+
+        if (found.length) return {
+            list: found,
+            from: CodeMirror.Pos(cur.line, token.start),
+            to: CodeMirror.Pos(cur.line, token.end)
+        };
+    });
+
+    CodeMirror.commands.autocomplete = CodeMirror.showHint;
+
+    var defaultOptions = {
+        hint: CodeMirror.hint.auto,
+        completeSingle: true,
+        alignWithWord: true,
+        closeCharacters: /[\s()\[\]{};:>,]/,
+        closeOnUnfocus: true,
+        completeOnSingleClick: true,
+        container: null,
+        customKeys: null,
+        extraKeys: null
+    };
+
+    CodeMirror.defineOption("hintOptions", null);
+});/**
+ * Farbtastic Color Picker 1.2
+ * © 2008 Steven Wittens
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+jQuery.fn.farbtastic = function (callback) {
+  $.farbtastic(this, callback);
+  return this;
+};
+
+jQuery.farbtastic = function (container, callback) {
+  var container = $(container).get(0);
+  return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));
+}
+
+jQuery._farbtastic = function (container, callback) {
+  // Store farbtastic object
+  var fb = this;
+
+  // Insert markup
+  $(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
+  var e = $('.farbtastic', container);
+  fb.wheel = $('.wheel', container).get(0);
+  // Dimensions
+  fb.radius = 84;
+  fb.square = 100;
+  fb.width = 194;
+
+  // Fix background PNGs in IE6
+  if (navigator.appVersion.match(/MSIE [0-6]\./)) {
+    $('*', e).each(function () {
+      if (this.currentStyle.backgroundImage != 'none') {
+        var image = this.currentStyle.backgroundImage;
+        image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
+        $(this).css({
+          'backgroundImage': 'none',
+          'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+        });
+      }
+    });
+  }
+
+  /**
+   * Link to the given element(s) or callback.
+   */
+  fb.linkTo = function (callback) {
+    // Unbind previous nodes
+    if (typeof fb.callback == 'object') {
+      $(fb.callback).unbind('keyup', fb.updateValue);
+    }
+
+    // Reset color
+    fb.color = null;
+
+    // Bind callback or elements
+    if (typeof callback == 'function') {
+      fb.callback = callback;
+    }
+    else if (typeof callback == 'object' || typeof callback == 'string') {
+      fb.callback = $(callback);
+      fb.callback.bind('keyup', fb.updateValue);
+      if (fb.callback.get(0).value) {
+        fb.setColor(fb.callback.get(0).value);
+      }
+    }
+    return this;
+  }
+  fb.updateValue = function (event) {
+    if (this.value && this.value != fb.color) {
+      fb.setColor(this.value);
+    }
+  }
+
+  /**
+   * Change color with HTML syntax #123456
+   */
+  fb.setColor = function (color) {
+    var unpack = fb.unpack(color);
+    if (fb.color != color && unpack) {
+      fb.color = color;
+      fb.rgb = unpack;
+      fb.hsl = fb.RGBToHSL(fb.rgb);
+      fb.updateDisplay();
+    }
+    return this;
+  }
+
+  /**
+   * Change color with HSL triplet [0..1, 0..1, 0..1]
+   */
+  fb.setHSL = function (hsl) {
+    fb.hsl = hsl;
+    fb.rgb = fb.HSLToRGB(hsl);
+    fb.color = fb.pack(fb.rgb);
+    fb.updateDisplay();
+    return this;
+  }
+
+  /////////////////////////////////////////////////////
+
+  /**
+   * Retrieve the coordinates of the given event relative to the center
+   * of the widget.
+   */
+  fb.widgetCoords = function (event) {
+    var x, y;
+    var el = event.target || event.srcElement;
+    var reference = fb.wheel;
+
+    if (typeof event.offsetX != 'undefined') {
+      // Use offset coordinates and find common offsetParent
+      var pos = { x: event.offsetX, y: event.offsetY };
+
+      // Send the coordinates upwards through the offsetParent chain.
+      var e = el;
+      while (e) {
+        e.mouseX = pos.x;
+        e.mouseY = pos.y;
+        pos.x += e.offsetLeft;
+        pos.y += e.offsetTop;
+        e = e.offsetParent;
+      }
+
+      // Look for the coordinates starting from the wheel widget.
+      var e = reference;
+      var offset = { x: 0, y: 0 }
+      while (e) {
+        if (typeof e.mouseX != 'undefined') {
+          x = e.mouseX - offset.x;
+          y = e.mouseY - offset.y;
+          break;
+        }
+        offset.x += e.offsetLeft;
+        offset.y += e.offsetTop;
+        e = e.offsetParent;
+      }
+
+      // Reset stored coordinates
+      e = el;
+      while (e) {
+        e.mouseX = undefined;
+        e.mouseY = undefined;
+        e = e.offsetParent;
+      }
+    }
+    else {
+      // Use absolute coordinates
+      var pos = fb.absolutePosition(reference);
+      x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x;
+      y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y;
+    }
+    // Subtract distance to middle
+    return { x: x - fb.width / 2, y: y - fb.width / 2 };
+  }
+
+  /**
+   * Mousedown handler
+   */
+  fb.mousedown = function (event) {
+    // Capture mouse
+    if (!document.dragging) {
+      $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
+      document.dragging = true;
+    }
+
+    // Check which area is being dragged
+    var pos = fb.widgetCoords(event);
+    fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
+
+    // Process
+    fb.mousemove(event);
+    return false;
+  }
+
+  /**
+   * Mousemove handler
+   */
+  fb.mousemove = function (event) {
+    // Get coordinates relative to color picker center
+    var pos = fb.widgetCoords(event);
+
+    // Set new HSL parameters
+    if (fb.circleDrag) {
+      var hue = Math.atan2(pos.x, -pos.y) / 6.28;
+      if (hue < 0) hue += 1;
+      fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
+    }
+    else {
+      var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
+      var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
+      fb.setHSL([fb.hsl[0], sat, lum]);
+    }
+    return false;
+  }
+
+  /**
+   * Mouseup handler
+   */
+  fb.mouseup = function () {
+    // Uncapture mouse
+    $(document).unbind('mousemove', fb.mousemove);
+    $(document).unbind('mouseup', fb.mouseup);
+    document.dragging = false;
+  }
+
+  /**
+   * Update the markers and styles
+   */
+  fb.updateDisplay = function () {
+    // Markers
+    var angle = fb.hsl[0] * 6.28;
+    $('.h-marker', e).css({
+      left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
+      top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
+    });
+
+    $('.sl-marker', e).css({
+      left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
+      top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
+    });
+
+    // Saturation/Luminance gradient
+    $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
+
+    // Linked elements or callback
+    if (typeof fb.callback == 'object') {
+      // Set background/foreground color
+      $(fb.callback).css({
+        backgroundColor: fb.color,
+        color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
+      });
+
+      // Change linked value
+      $(fb.callback).each(function() {
+        if (this.value && this.value != fb.color) {
+          this.value = fb.color;
+        }
+      });
+    }
+    else if (typeof fb.callback == 'function') {
+      fb.callback.call(fb, fb.color);
+    }
+  }
+
+  /**
+   * Get absolute position of element
+   */
+  fb.absolutePosition = function (el) {
+    var r = { x: el.offsetLeft, y: el.offsetTop };
+    // Resolve relative to offsetParent
+    if (el.offsetParent) {
+      var tmp = fb.absolutePosition(el.offsetParent);
+      r.x += tmp.x;
+      r.y += tmp.y;
+    }
+    return r;
+  };
+
+  /* Various color utility functions */
+  fb.pack = function (rgb) {
+    var r = Math.round(rgb[0] * 255);
+    var g = Math.round(rgb[1] * 255);
+    var b = Math.round(rgb[2] * 255);
+    return '#' + (r < 16 ? '0' : '') + r.toString(16) +
+           (g < 16 ? '0' : '') + g.toString(16) +
+           (b < 16 ? '0' : '') + b.toString(16);
+  }
+
+  fb.unpack = function (color) {
+    if (color.length == 7) {
+      return [parseInt('0x' + color.substring(1, 3)) / 255,
+        parseInt('0x' + color.substring(3, 5)) / 255,
+        parseInt('0x' + color.substring(5, 7)) / 255];
+    }
+    else if (color.length == 4) {
+      return [parseInt('0x' + color.substring(1, 2)) / 15,
+        parseInt('0x' + color.substring(2, 3)) / 15,
+        parseInt('0x' + color.substring(3, 4)) / 15];
+    }
+  }
+
+  fb.HSLToRGB = function (hsl) {
+    var m1, m2, r, g, b;
+    var h = hsl[0], s = hsl[1], l = hsl[2];
+    m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
+    m1 = l * 2 - m2;
+    return [this.hueToRGB(m1, m2, h+0.33333),
+        this.hueToRGB(m1, m2, h),
+        this.hueToRGB(m1, m2, h-0.33333)];
+  }
+
+  fb.hueToRGB = function (m1, m2, h) {
+    h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
+    if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
+    if (h * 2 < 1) return m2;
+    if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
+    return m1;
+  }
+
+  fb.RGBToHSL = function (rgb) {
+    var min, max, delta, h, s, l;
+    var r = rgb[0], g = rgb[1], b = rgb[2];
+    min = Math.min(r, Math.min(g, b));
+    max = Math.max(r, Math.max(g, b));
+    delta = max - min;
+    l = (min + max) / 2;
+    s = 0;
+    if (l > 0 && l < 1) {
+      s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
+    }
+    h = 0;
+    if (delta > 0) {
+      if (max == r && max != g) h += (g - b) / delta;
+      if (max == g && max != b) h += (2 + (b - r) / delta);
+      if (max == b && max != r) h += (4 + (r - g) / delta);
+      h /= 6;
+    }
+    return [h, s, l];
+  }
+
+  // Install mousedown handler (the others are set on the document on-demand)
+  $('*', e).mousedown(fb.mousedown);
+
+    // Init color
+  fb.setColor('#000000');
+
+  // Set linked elements/callback
+  if (callback) {
+    fb.linkTo(callback);
+  }
+}/*!
+ * jQuery Mousewheel 3.1.13
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ */
+
+(function (factory) {
+    if ( typeof define === 'function' && define.amd ) {
+        // AMD. Register as an anonymous module.
+        define(['../core/jquery'], factory);
+    } else if (typeof exports === 'object') {
+        // Node/CommonJS style for Browserify
+        module.exports = factory;
+    } else {
+        // Browser globals
+        factory(jQuery);
+    }
+}(function ($) {
+
+    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
+        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
+                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
+        slice  = Array.prototype.slice,
+        nullLowestDeltaTimeout, lowestDelta;
+
+    if ( $.event.fixHooks ) {
+        for ( var i = toFix.length; i; ) {
+            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
+        }
+    }
+
+    var special = $.event.special.mousewheel = {
+        version: '3.1.12',
+
+        setup: function() {
+            if ( this.addEventListener ) {
+                for ( var i = toBind.length; i; ) {
+                    this.addEventListener( toBind[--i], handler, false );
+                }
+            } else {
+                this.onmousewheel = handler;
+            }
+            // Store the line height and page height for this particular element
+            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
+            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
+        },
+
+        teardown: function() {
+            if ( this.removeEventListener ) {
+                for ( var i = toBind.length; i; ) {
+                    this.removeEventListener( toBind[--i], handler, false );
+                }
+            } else {
+                this.onmousewheel = null;
+            }
+            // Clean up the data we added to the element
+            $.removeData(this, 'mousewheel-line-height');
+            $.removeData(this, 'mousewheel-page-height');
+        },
+
+        getLineHeight: function(elem) {
+            var $elem = $(elem),
+                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
+            if (!$parent.length) {
+                $parent = $('body');
+            }
+            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
+        },
+
+        getPageHeight: function(elem) {
+            return $(elem).height();
+        },
+
+        settings: {
+            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
+            normalizeOffset: true  // calls getBoundingClientRect for each event
+        }
+    };
+
+    $.fn.extend({
+        mousewheel: function(fn) {
+            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
+        },
+
+        unmousewheel: function(fn) {
+            return this.unbind('mousewheel', fn);
+        }
+    });
+
+
+    function handler(event) {
+        var orgEvent   = event || window.event,
+            args       = slice.call(arguments, 1),
+            delta      = 0,
+            deltaX     = 0,
+            deltaY     = 0,
+            absDelta   = 0,
+            offsetX    = 0,
+            offsetY    = 0;
+        event = $.event.fix(orgEvent);
+        event.type = 'mousewheel';
+
+        // Old school scrollwheel delta
+        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
+        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
+        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
+        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
+
+        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
+        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
+            deltaX = deltaY * -1;
+            deltaY = 0;
+        }
+
+        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
+        delta = deltaY === 0 ? deltaX : deltaY;
+
+        // New school wheel delta (wheel event)
+        if ( 'deltaY' in orgEvent ) {
+            deltaY = orgEvent.deltaY * -1;
+            delta  = deltaY;
+        }
+        if ( 'deltaX' in orgEvent ) {
+            deltaX = orgEvent.deltaX;
+            if ( deltaY === 0 ) { delta  = deltaX * -1; }
+        }
+
+        // No change actually happened, no reason to go any further
+        if ( deltaY === 0 && deltaX === 0 ) { return; }
+
+        // Need to convert lines and pages to pixels if we aren't already in pixels
+        // There are three delta modes:
+        //   * deltaMode 0 is by pixels, nothing to do
+        //   * deltaMode 1 is by lines
+        //   * deltaMode 2 is by pages
+        if ( orgEvent.deltaMode === 1 ) {
+            var lineHeight = $.data(this, 'mousewheel-line-height');
+            delta  *= lineHeight;
+            deltaY *= lineHeight;
+            deltaX *= lineHeight;
+        } else if ( orgEvent.deltaMode === 2 ) {
+            var pageHeight = $.data(this, 'mousewheel-page-height');
+            delta  *= pageHeight;
+            deltaY *= pageHeight;
+            deltaX *= pageHeight;
+        }
+
+        // Store lowest absolute delta to normalize the delta values
+        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
+
+        if ( !lowestDelta || absDelta < lowestDelta ) {
+            lowestDelta = absDelta;
+
+            // Adjust older deltas if necessary
+            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
+                lowestDelta /= 40;
+            }
+        }
+
+        // Adjust older deltas if necessary
+        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
+            // Divide all the things by 40!
+            delta  /= 40;
+            deltaX /= 40;
+            deltaY /= 40;
+        }
+
+        // Get a whole, normalized value for the deltas
+        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
+        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
+        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
+
+        // Normalise offsetX and offsetY properties
+        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
+            var boundingRect = this.getBoundingClientRect();
+            offsetX = event.clientX - boundingRect.left;
+            offsetY = event.clientY - boundingRect.top;
+        }
+
+        // Add information to the event object
+        event.deltaX = deltaX;
+        event.deltaY = deltaY;
+        event.deltaFactor = lowestDelta;
+        event.offsetX = offsetX;
+        event.offsetY = offsetY;
+        // Go ahead and set deltaMode to 0 since we converted to pixels
+        // Although this is a little odd since we overwrite the deltaX/Y
+        // properties with normalized deltas.
+        event.deltaMode = 0;
+
+        // Add event and delta to the front of the arguments
+        args.unshift(event, delta, deltaX, deltaY);
+
+        // Clearout lowestDelta after sometime to better
+        // handle multiple device types that give different
+        // a different lowestDelta
+        // Ex: trackpad = 3 and mouse wheel = 120
+        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
+        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
+
+        return ($.event.dispatch || $.event.handle).apply(this, args);
+    }
+
+    function nullLowestDelta() {
+        lowestDelta = null;
+    }
+
+    function shouldAdjustOldDeltas(orgEvent, absDelta) {
+        // If this is an older event and the delta is divisable by 120,
+        // then we are assuming that the browser is treating this as an
+        // older mouse wheel event and that we should divide the deltas
+        // by 40 to try and get a more usable deltaFactor.
+        // Side note, this actually impacts the reported scroll distance
+        // in older browsers and can cause scrolling to be slower than native.
+        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
+        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
+    }
+
+}));// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+// ┌────────────────────────────────────────────────────────────┐ \\
+// │ Eve 0.4.2 - JavaScript Events Library                      │ \\
+// ├────────────────────────────────────────────────────────────┤ \\
+// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
+// └────────────────────────────────────────────────────────────┘ \\
+(function (glob, factory) {
+    if (typeof define === "function" && define.amd) {
+        define("eve", function() {
+            return factory();
+        });
+    } else if (typeof exports === "object") {
+        module.exports = factory();
+    } else {
+        glob.eve = factory();
+    }
+}(this, function(){
+    var version = "0.4.2",
+        has = "hasOwnProperty",
+        separator = /[\.\/]/,
+        wildcard = "*",
+        fun = function () {},
+        numsort = function (a, b) {
+            return a - b;
+        },
+        current_event,
+        stop,
+        events = {n: {}},
+    /*\
+     * eve
+     [ method ]
+
+     * Fires event with given `name`, given scope and other parameters.
+
+     > Arguments
+
+     - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
+     - scope (object) context for the event handlers
+     - varargs (...) the rest of arguments will be sent to event handlers
+
+     = (object) array of returned values from the listeners
+     \*/
+        eve = function (name, scope) {
+            name = String(name);
+            var e = events,
+                oldstop = stop,
+                args = Array.prototype.slice.call(arguments, 2),
+                listeners = eve.listeners(name),
+                z = 0,
+                f = false,
+                l,
+                indexed = [],
+                queue = {},
+                out = [],
+                ce = current_event,
+                errors = [];
+            current_event = name;
+            stop = 0;
+            for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
+                indexed.push(listeners[i].zIndex);
+                if (listeners[i].zIndex < 0) {
+                    queue[listeners[i].zIndex] = listeners[i];
+                }
+            }
+            indexed.sort(numsort);
+            while (indexed[z] < 0) {
+                l = queue[indexed[z++]];
+                out.push(l.apply(scope, args));
+                if (stop) {
+                    stop = oldstop;
+                    return out;
+                }
+            }
+            for (i = 0; i < ii; i++) {
+                l = listeners[i];
+                if ("zIndex" in l) {
+                    if (l.zIndex == indexed[z]) {
+                        out.push(l.apply(scope, args));
+                        if (stop) {
+                            break;
+                        }
+                        do {
+                            z++;
+                            l = queue[indexed[z]];
+                            l && out.push(l.apply(scope, args));
+                            if (stop) {
+                                break;
+                            }
+                        } while (l)
+                    } else {
+                        queue[l.zIndex] = l;
+                    }
+                } else {
+                    out.push(l.apply(scope, args));
+                    if (stop) {
+                        break;
+                    }
+                }
+            }
+            stop = oldstop;
+            current_event = ce;
+            return out.length ? out : null;
+        };
+    // Undocumented. Debug only.
+    eve._events = events;
+    /*\
+     * eve.listeners
+     [ method ]
+
+     * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
+
+     > Arguments
+
+     - name (string) name of the event, dot (`.`) or slash (`/`) separated
+
+     = (array) array of event handlers
+     \*/
+    eve.listeners = function (name) {
+        var names = name.split(separator),
+            e = events,
+            item,
+            items,
+            k,
+            i,
+            ii,
+            j,
+            jj,
+            nes,
+            es = [e],
+            out = [];
+        for (i = 0, ii = names.length; i < ii; i++) {
+            nes = [];
+            for (j = 0, jj = es.length; j < jj; j++) {
+                e = es[j].n;
+                items = [e[names[i]], e[wildcard]];
+                k = 2;
+                while (k--) {
+                    item = items[k];
+                    if (item) {
+                        nes.push(item);
+                        out = out.concat(item.f || []);
+                    }
+                }
+            }
+            es = nes;
+        }
+        return out;
+    };
+
+    /*\
+     * eve.on
+     [ method ]
+     **
+     * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
+     | eve.on("*.under.*", f);
+     | eve("mouse.under.floor"); // triggers f
+     * Use @eve to trigger the listener.
+     **
+     > Arguments
+     **
+     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+     - f (function) event handler function
+     **
+     = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+     > Example:
+     | eve.on("mouse", eatIt)(2);
+     | eve.on("mouse", scream);
+     | eve.on("mouse", catchIt)(1);
+     * This will ensure that `catchIt()` function will be called before `eatIt()`.
+     *
+     * If you want to put your handler before non-indexed handlers, specify a negative value.
+     * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+     \*/
+    eve.on = function (name, f) {
+        name = String(name);
+        if (typeof f != "function") {
+            return function () {};
+        }
+        var names = name.split(separator),
+            e = events;
+        for (var i = 0, ii = names.length; i < ii; i++) {
+            e = e.n;
+            e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
+        }
+        e.f = e.f || [];
+        for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
+            return fun;
+        }
+        e.f.push(f);
+        return function (zIndex) {
+            if (+zIndex == +zIndex) {
+                f.zIndex = +zIndex;
+            }
+        };
+    };
+    /*\
+     * eve.f
+     [ method ]
+     **
+     * Returns function that will fire given event with optional arguments.
+     * Arguments that will be passed to the result function will be also
+     * concated to the list of final arguments.
+     | el.onclick = eve.f("click", 1, 2);
+     | eve.on("click", function (a, b, c) {
+     |     console.log(a, b, c); // 1, 2, [event object]
+     | });
+     > Arguments
+     - event (string) event name
+     - varargs (…) and any other arguments
+     = (function) possible event handler function
+     \*/
+    eve.f = function (event) {
+        var attrs = [].slice.call(arguments, 1);
+        return function () {
+            eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
+        };
+    };
+    /*\
+     * eve.stop
+     [ method ]
+     **
+     * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+     \*/
+    eve.stop = function () {
+        stop = 1;
+    };
+    /*\
+     * eve.nt
+     [ method ]
+     **
+     * Could be used inside event handler to figure out actual name of the event.
+     **
+     > Arguments
+     **
+     - subname (string) #optional subname of the event
+     **
+     = (string) name of the event, if `subname` is not specified
+     * or
+     = (boolean) `true`, if current event’s name contains `subname`
+     \*/
+    eve.nt = function (subname) {
+        if (subname) {
+            return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
+        }
+        return current_event;
+    };
+    /*\
+     * eve.nts
+     [ method ]
+     **
+     * Could be used inside event handler to figure out actual name of the event.
+     **
+     **
+     = (array) names of the event
+     \*/
+    eve.nts = function () {
+        return current_event.split(separator);
+    };
+    /*\
+     * eve.off
+     [ method ]
+     **
+     * Removes given function from the list of event listeners assigned to given name.
+     * If no arguments specified all the events will be cleared.
+     **
+     > Arguments
+     **
+     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+     - f (function) event handler function
+     \*/
+    /*\
+     * eve.unbind
+     [ method ]
+     **
+     * See @eve.off
+     \*/
+    eve.off = eve.unbind = function (name, f) {
+        if (!name) {
+            eve._events = events = {n: {}};
+            return;
+        }
+        var names = name.split(separator),
+            e,
+            key,
+            splice,
+            i, ii, j, jj,
+            cur = [events];
+        for (i = 0, ii = names.length; i < ii; i++) {
+            for (j = 0; j < cur.length; j += splice.length - 2) {
+                splice = [j, 1];
+                e = cur[j].n;
+                if (names[i] != wildcard) {
+                    if (e[names[i]]) {
+                        splice.push(e[names[i]]);
+                    }
+                } else {
+                    for (key in e) if (e[has](key)) {
+                        splice.push(e[key]);
+                    }
+                }
+                cur.splice.apply(cur, splice);
+            }
+        }
+        for (i = 0, ii = cur.length; i < ii; i++) {
+            e = cur[i];
+            while (e.n) {
+                if (f) {
+                    if (e.f) {
+                        for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
+                            e.f.splice(j, 1);
+                            break;
+                        }
+                        !e.f.length && delete e.f;
+                    }
+                    for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+                        var funcs = e.n[key].f;
+                        for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
+                            funcs.splice(j, 1);
+                            break;
+                        }
+                        !funcs.length && delete e.n[key].f;
+                    }
+                } else {
+                    delete e.f;
+                    for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+                        delete e.n[key].f;
+                    }
+                }
+                e = e.n;
+            }
+        }
+    };
+    /*\
+     * eve.once
+     [ method ]
+     **
+     * Binds given event handler with a given name to only run once then unbind itself.
+     | eve.once("login", f);
+     | eve("login"); // triggers f
+     | eve("login"); // no listeners
+     * Use @eve to trigger the listener.
+     **
+     > Arguments
+     **
+     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+     - f (function) event handler function
+     **
+     = (function) same return function as @eve.on
+     \*/
+    eve.once = function (name, f) {
+        var f2 = function () {
+            eve.unbind(name, f2);
+            return f.apply(this, arguments);
+        };
+        return eve.on(name, f2);
+    };
+    /*\
+     * eve.version
+     [ property (string) ]
+     **
+     * Current version of the library.
+     \*/
+    eve.version = version;
+    eve.toString = function () {
+        return "You are running Eve " + version;
+    };
+
+    return eve;
+}));
+
+// ┌────────────────────────────────────────────────────────────────────┐ \\
+// │ Raphaël 2.1.4 - JavaScript Vector Library                      │ \\
+// ├────────────────────────────────────────────────────────────────────┤ \\
+// │ Core Module                                                        │ \\
+// ├────────────────────────────────────────────────────────────────────┤ \\
+// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\
+// └────────────────────────────────────────────────────────────────────┘ \\
+
+(function (glob, factory) {
+    if (typeof define === "function" && define.amd) {
+        define("raphael.core", ["eve"], function(eve) {
+            return factory(eve);
+        });
+    } else if (typeof exports === "object") {
+        module.exports = factory(require("eve"));
+    } else {
+        glob.Raphael = factory(glob.eve);
+    }
+}(this, function (eve) {
+    /*\
+     * Raphael
+     [ method ]
+     **
+     * Creates a canvas object on which to draw.
+     * You must do this first, as all future calls to drawing methods
+     * from this instance will be bound to this canvas.
+     > Parameters
+     **
+     - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface
+     - width (number)
+     - height (number)
+     - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+     * or
+     - x (number)
+     - y (number)
+     - width (number)
+     - height (number)
+     - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+     * or
+     - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, <attributes>}). See @Paper.add.
+     - callback (function) #optional callback function which is going to be executed in the context of newly created paper
+     * or
+     - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`.
+     = (object) @Paper
+     > Usage
+     | // Each of the following examples create a canvas
+     | // that is 320px wide by 200px high.
+     | // Canvas is created at the viewport’s 10,50 coordinate.
+     | var paper = Raphael(10, 50, 320, 200);
+     | // Canvas is created at the top left corner of the #notepad element
+     | // (or its top right corner in dir="rtl" elements)
+     | var paper = Raphael(document.getElementById("notepad"), 320, 200);
+     | // Same as above
+     | var paper = Raphael("notepad", 320, 200);
+     | // Image dump
+     | var set = Raphael(["notepad", 320, 200, {
+     |     type: "rect",
+     |     x: 10,
+     |     y: 10,
+     |     width: 25,
+     |     height: 25,
+     |     stroke: "#f00"
+     | }, {
+     |     type: "text",
+     |     x: 30,
+     |     y: 40,
+     |     text: "Dump"
+     | }]);
+     \*/
+    function R(first) {
+        if (R.is(first, "function")) {
+            return loaded ? first() : eve.on("raphael.DOMload", first);
+        } else if (R.is(first, array)) {
+            return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first);
+        } else {
+            var args = Array.prototype.slice.call(arguments, 0);
+            if (R.is(args[args.length - 1], "function")) {
+                var f = args.pop();
+                return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("raphael.DOMload", function () {
+                    f.call(R._engine.create[apply](R, args));
+                });
+            } else {
+                return R._engine.create[apply](R, arguments);
+            }
+        }
+    }
+    R.version = "2.1.4";
+    R.eve = eve;
+    var loaded,
+        separator = /[, ]+/,
+        elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1},
+        formatrg = /\{(\d+)\}/g,
+        proto = "prototype",
+        has = "hasOwnProperty",
+        g = {
+            doc: document,
+            win: window
+        },
+        oldRaphael = {
+            was: Object.prototype[has].call(g.win, "Raphael"),
+            is: g.win.Raphael
+        },
+        Paper = function () {
+            /*\
+             * Paper.ca
+             [ property (object) ]
+             **
+             * Shortcut for @Paper.customAttributes
+             \*/
+            /*\
+             * Paper.customAttributes
+             [ property (object) ]
+             **
+             * If you have a set of attributes that you would like to represent
+             * as a function of some number you can do it easily with custom attributes:
+             > Usage
+             | paper.customAttributes.hue = function (num) {
+             |     num = num % 1;
+             |     return {fill: "hsb(" + num + ", 0.75, 1)"};
+             | };
+             | // Custom attribute “hue” will change fill
+             | // to be given hue with fixed saturation and brightness.
+             | // Now you can use it like this:
+             | var c = paper.circle(10, 10, 10).attr({hue: .45});
+             | // or even like this:
+             | c.animate({hue: 1}, 1e3);
+             |
+             | // You could also create custom attribute
+             | // with multiple parameters:
+             | paper.customAttributes.hsb = function (h, s, b) {
+             |     return {fill: "hsb(" + [h, s, b].join(",") + ")"};
+             | };
+             | c.attr({hsb: "0.5 .8 1"});
+             | c.animate({hsb: [1, 0, 0.5]}, 1e3);
+             \*/
+            this.ca = this.customAttributes = {};
+        },
+        paperproto,
+        appendChild = "appendChild",
+        apply = "apply",
+        concat = "concat",
+        supportsTouch = ('ontouchstart' in g.win) || g.win.DocumentTouch && g.doc instanceof DocumentTouch, //taken from Modernizr touch test
+        E = "",
+        S = " ",
+        Str = String,
+        split = "split",
+        events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S),
+        touchMap = {
+            mousedown: "touchstart",
+            mousemove: "touchmove",
+            mouseup: "touchend"
+        },
+        lowerCase = Str.prototype.toLowerCase,
+        math = Math,
+        mmax = math.max,
+        mmin = math.min,
+        abs = math.abs,
+        pow = math.pow,
+        PI = math.PI,
+        nu = "number",
+        string = "string",
+        array = "array",
+        toString = "toString",
+        fillString = "fill",
+        objectToString = Object.prototype.toString,
+        paper = {},
+        push = "push",
+        ISURL = R._ISURL = /^url\(['"]?(.+?)['"]?\)$/i,
+        colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i,
+        isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1},
+        bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
+        round = math.round,
+        setAttribute = "setAttribute",
+        toFloat = parseFloat,
+        toInt = parseInt,
+        upperCase = Str.prototype.toUpperCase,
+        availableAttrs = R._availableAttrs = {
+            "arrow-end": "none",
+            "arrow-start": "none",
+            blur: 0,
+            "clip-rect": "0 0 1e9 1e9",
+            cursor: "default",
+            cx: 0,
+            cy: 0,
+            fill: "#fff",
+            "fill-opacity": 1,
+            font: '10px "Arial"',
+            "font-family": '"Arial"',
+            "font-size": "10",
+            "font-style": "normal",
+            "font-weight": 400,
+            gradient: 0,
+            height: 0,
+            href: "http://raphaeljs.com/",
+            "letter-spacing": 0,
+            opacity: 1,
+            path: "M0,0",
+            r: 0,
+            rx: 0,
+            ry: 0,
+            src: "",
+            stroke: "#000",
+            "stroke-dasharray": "",
+            "stroke-linecap": "butt",
+            "stroke-linejoin": "butt",
+            "stroke-miterlimit": 0,
+            "stroke-opacity": 1,
+            "stroke-width": 1,
+            target: "_blank",
+            "text-anchor": "middle",
+            title: "Raphael",
+            transform: "",
+            width: 0,
+            x: 0,
+            y: 0
+        },
+        availableAnimAttrs = R._availableAnimAttrs = {
+            blur: nu,
+            "clip-rect": "csv",
+            cx: nu,
+            cy: nu,
+            fill: "colour",
+            "fill-opacity": nu,
+            "font-size": nu,
+            height: nu,
+            opacity: nu,
+            path: "path",
+            r: nu,
+            rx: nu,
+            ry: nu,
+            stroke: "colour",
+            "stroke-opacity": nu,
+            "stroke-width": nu,
+            transform: "transform",
+            width: nu,
+            x: nu,
+            y: nu
+        },
+        whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g,
+        commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,
+        hsrg = {hs: 1, rg: 1},
+        p2s = /,?([achlmqrstvxz]),?/gi,
+        pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+        tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,
+        pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig,
+        radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/,
+        eldata = {},
+        sortByKey = function (a, b) {
+            return a.key - b.key;
+        },
+        sortByNumber = function (a, b) {
+            return toFloat(a) - toFloat(b);
+        },
+        fun = function () {},
+        pipe = function (x) {
+            return x;
+        },
+        rectPath = R._rectPath = function (x, y, w, h, r) {
+            if (r) {
+                return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]];
+            }
+            return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
+        },
+        ellipsePath = function (x, y, rx, ry) {
+            if (ry == null) {
+                ry = rx;
+            }
+            return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]];
+        },
+        getPath = R._getPath = {
+            path: function (el) {
+                return el.attr("path");
+            },
+            circle: function (el) {
+                var a = el.attrs;
+                return ellipsePath(a.cx, a.cy, a.r);
+            },
+            ellipse: function (el) {
+                var a = el.attrs;
+                return ellipsePath(a.cx, a.cy, a.rx, a.ry);
+            },
+            rect: function (el) {
+                var a = el.attrs;
+                return rectPath(a.x, a.y, a.width, a.height, a.r);
+            },
+            image: function (el) {
+                var a = el.attrs;
+                return rectPath(a.x, a.y, a.width, a.height);
+            },
+            text: function (el) {
+                var bbox = el._getBBox();
+                return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
+            },
+            set : function(el) {
+                var bbox = el._getBBox();
+                return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
+            }
+        },
+    /*\
+     * Raphael.mapPath
+     [ method ]
+     **
+     * Transform the path string with given matrix.
+     > Parameters
+     - path (string) path string
+     - matrix (object) see @Matrix
+     = (string) transformed path string
+     \*/
+        mapPath = R.mapPath = function (path, matrix) {
+            if (!matrix) {
+                return path;
+            }
+            var x, y, i, j, ii, jj, pathi;
+            path = path2curve(path);
+            for (i = 0, ii = path.length; i < ii; i++) {
+                pathi = path[i];
+                for (j = 1, jj = pathi.length; j < jj; j += 2) {
+                    x = matrix.x(pathi[j], pathi[j + 1]);
+                    y = matrix.y(pathi[j], pathi[j + 1]);
+                    pathi[j] = x;
+                    pathi[j + 1] = y;
+                }
+            }
+            return path;
+        };
+
+    R._g = g;
+    /*\
+     * Raphael.type
+     [ property (string) ]
+     **
+     * Can be “SVG”, “VML” or empty, depending on browser support.
+     \*/
+    R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");
+    if (R.type == "VML") {
+        var d = g.doc.createElement("div"),
+            b;
+        d.innerHTML = '<v:shape adj="1"/>';
+        b = d.firstChild;
+        b.style.behavior = "url(#default#VML)";
+        if (!(b && typeof b.adj == "object")) {
+            return (R.type = E);
+        }
+        d = null;
+    }
+    /*\
+     * Raphael.svg
+     [ property (boolean) ]
+     **
+     * `true` if browser supports SVG.
+     \*/
+    /*\
+     * Raphael.vml
+     [ property (boolean) ]
+     **
+     * `true` if browser supports VML.
+     \*/
+    R.svg = !(R.vml = R.type == "VML");
+    R._Paper = Paper;
+    /*\
+     * Raphael.fn
+     [ property (object) ]
+     **
+     * You can add your own method to the canvas. For example if you want to draw a pie chart,
+     * you can create your own pie chart function and ship it as a Raphaël plugin. To do this
+     * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a
+     * Raphaël instance is created, otherwise it will take no effect. Please note that the
+     * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to
+     * ensure any namespacing ensures proper context.
+     > Usage
+     | Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
+     |     return this.path( ... );
+     | };
+     | // or create namespace
+     | Raphael.fn.mystuff = {
+     |     arrow: function () {…},
+     |     star: function () {…},
+     |     // etc…
+     | };
+     | var paper = Raphael(10, 10, 630, 480);
+     | // then use it
+     | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
+     | paper.mystuff.arrow();
+     | paper.mystuff.star();
+     \*/
+    R.fn = paperproto = Paper.prototype = R.prototype;
+    R._id = 0;
+    R._oid = 0;
+    /*\
+     * Raphael.is
+     [ method ]
+     **
+     * Handful of replacements for `typeof` operator.
+     > Parameters
+     - o (…) any object or primitive
+     - type (string) name of the type, i.e. “string”, “function”, “number”, etc.
+     = (boolean) is given value is of given type
+     \*/
+    R.is = function (o, type) {
+        type = lowerCase.call(type);
+        if (type == "finite") {
+            return !isnan[has](+o);
+        }
+        if (type == "array") {
+            return o instanceof Array;
+        }
+        return  (type == "null" && o === null) ||
+            (type == typeof o && o !== null) ||
+            (type == "object" && o === Object(o)) ||
+            (type == "array" && Array.isArray && Array.isArray(o)) ||
+            objectToString.call(o).slice(8, -1).toLowerCase() == type;
+    };
+
+    function clone(obj) {
+        if (typeof obj == "function" || Object(obj) !== obj) {
+            return obj;
+        }
+        var res = new obj.constructor;
+        for (var key in obj) if (obj[has](key)) {
+            res[key] = clone(obj[key]);
+        }
+        return res;
+    }
+
+    /*\
+     * Raphael.angle
+     [ method ]
+     **
+     * Returns angle between two or three points
+     > Parameters
+     - x1 (number) x coord of first point
+     - y1 (number) y coord of first point
+     - x2 (number) x coord of second point
+     - y2 (number) y coord of second point
+     - x3 (number) #optional x coord of third point
+     - y3 (number) #optional y coord of third point
+     = (number) angle in degrees.
+     \*/
+    R.angle = function (x1, y1, x2, y2, x3, y3) {
+        if (x3 == null) {
+            var x = x1 - x2,
+                y = y1 - y2;
+            if (!x && !y) {
+                return 0;
+            }
+            return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
+        } else {
+            return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3);
+        }
+    };
+    /*\
+     * Raphael.rad
+     [ method ]
+     **
+     * Transform angle to radians
+     > Parameters
+     - deg (number) angle in degrees
+     = (number) angle in radians.
+     \*/
+    R.rad = function (deg) {
+        return deg % 360 * PI / 180;
+    };
+    /*\
+     * Raphael.deg
+     [ method ]
+     **
+     * Transform angle to degrees
+     > Parameters
+     - rad (number) angle in radians
+     = (number) angle in degrees.
+     \*/
+    R.deg = function (rad) {
+        return Math.round ((rad * 180 / PI% 360)* 1000) / 1000;
+    };
+    /*\
+     * Raphael.snapTo
+     [ method ]
+     **
+     * Snaps given value to given grid.
+     > Parameters
+     - values (array|number) given array of values or step of the grid
+     - value (number) value to adjust
+     - tolerance (number) #optional tolerance for snapping. Default is `10`.
+     = (number) adjusted value.
+     \*/
+    R.snapTo = function (values, value, tolerance) {
+        tolerance = R.is(tolerance, "finite") ? tolerance : 10;
+        if (R.is(values, array)) {
+            var i = values.length;
+            while (i--) if (abs(values[i] - value) <= tolerance) {
+                return values[i];
+            }
+        } else {
+            values = +values;
+            var rem = value % values;
+            if (rem < tolerance) {
+                return value - rem;
+            }
+            if (rem > values - tolerance) {
+                return value - rem + values;
+            }
+        }
+        return value;
+    };
+
+    /*\
+     * Raphael.createUUID
+     [ method ]
+     **
+     * Returns RFC4122, version 4 ID
+     \*/
+    var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) {
+        return function () {
+            return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase();
+        };
+    })(/[xy]/g, function (c) {
+        var r = math.random() * 16 | 0,
+            v = c == "x" ? r : (r & 3 | 8);
+        return v.toString(16);
+    });
+
+    /*\
+     * Raphael.setWindow
+     [ method ]
+     **
+     * Used when you need to draw in `&lt;iframe>`. Switched window to the iframe one.
+     > Parameters
+     - newwin (window) new window object
+     \*/
+    R.setWindow = function (newwin) {
+        eve("raphael.setWindow", R, g.win, newwin);
+        g.win = newwin;
+        g.doc = g.win.document;
+        if (R._engine.initWin) {
+            R._engine.initWin(g.win);
+        }
+    };
+    var toHex = function (color) {
+            if (R.vml) {
+                // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
+                var trim = /^\s+|\s+$/g;
+                var bod;
+                try {
+                    var docum = new ActiveXObject("htmlfile");
+                    docum.write("<body>");
+                    docum.close();
+                    bod = docum.body;
+                } catch(e) {
+                    bod = createPopup().document.body;
+                }
+                var range = bod.createTextRange();
+                toHex = cacher(function (color) {
+                    try {
+                        bod.style.color = Str(color).replace(trim, E);
+                        var value = range.queryCommandValue("ForeColor");
+                        value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
+                        return "#" + ("000000" + value.toString(16)).slice(-6);
+                    } catch(e) {
+                        return "none";
+                    }
+                });
+            } else {
+                var i = g.doc.createElement("i");
+                i.title = "Rapha\xebl Colour Picker";
+                i.style.display = "none";
+                g.doc.body.appendChild(i);
+                toHex = cacher(function (color) {
+                    i.style.color = color;
+                    return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
+                });
+            }
+            return toHex(color);
+        },
+        hsbtoString = function () {
+            return "hsb(" + [this.h, this.s, this.b] + ")";
+        },
+        hsltoString = function () {
+            return "hsl(" + [this.h, this.s, this.l] + ")";
+        },
+        rgbtoString = function () {
+            return this.hex;
+        },
+        prepareRGB = function (r, g, b) {
+            if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) {
+                b = r.b;
+                g = r.g;
+                r = r.r;
+            }
+            if (g == null && R.is(r, string)) {
+                var clr = R.getRGB(r);
+                r = clr.r;
+                g = clr.g;
+                b = clr.b;
+            }
+            if (r > 1 || g > 1 || b > 1) {
+                r /= 255;
+                g /= 255;
+                b /= 255;
+            }
+
+            return [r, g, b];
+        },
+        packageRGB = function (r, g, b, o) {
+            r *= 255;
+            g *= 255;
+            b *= 255;
+            var rgb = {
+                r: r,
+                g: g,
+                b: b,
+                hex: R.rgb(r, g, b),
+                toString: rgbtoString
+            };
+            R.is(o, "finite") && (rgb.opacity = o);
+            return rgb;
+        };
+
+    /*\
+     * Raphael.color
+     [ method ]
+     **
+     * Parses the color string and returns object with all values for the given color.
+     > Parameters
+     - clr (string) color string in one of the supported formats (see @Raphael.getRGB)
+     = (object) Combined RGB & HSB object in format:
+     o {
+     o     r (number) red,
+     o     g (number) green,
+     o     b (number) blue,
+     o     hex (string) color in HTML/CSS format: #••••••,
+     o     error (boolean) `true` if string can’t be parsed,
+     o     h (number) hue,
+     o     s (number) saturation,
+     o     v (number) value (brightness),
+     o     l (number) lightness
+     o }
+     \*/
+    R.color = function (clr) {
+        var rgb;
+        if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
+            rgb = R.hsb2rgb(clr);
+            clr.r = rgb.r;
+            clr.g = rgb.g;
+            clr.b = rgb.b;
+            clr.hex = rgb.hex;
+        } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
+            rgb = R.hsl2rgb(clr);
+            clr.r = rgb.r;
+            clr.g = rgb.g;
+            clr.b = rgb.b;
+            clr.hex = rgb.hex;
+        } else {
+            if (R.is(clr, "string")) {
+                clr = R.getRGB(clr);
+            }
+            if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) {
+                rgb = R.rgb2hsl(clr);
+                clr.h = rgb.h;
+                clr.s = rgb.s;
+                clr.l = rgb.l;
+                rgb = R.rgb2hsb(clr);
+                clr.v = rgb.b;
+            } else {
+                clr = {hex: "none"};
+                clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
+            }
+        }
+        clr.toString = rgbtoString;
+        return clr;
+    };
+    /*\
+     * Raphael.hsb2rgb
+     [ method ]
+     **
+     * Converts HSB values to RGB object.
+     > Parameters
+     - h (number) hue
+     - s (number) saturation
+     - v (number) value or brightness
+     = (object) RGB object in format:
+     o {
+     o     r (number) red,
+     o     g (number) green,
+     o     b (number) blue,
+     o     hex (string) color in HTML/CSS format: #••••••
+     o }
+     \*/
+    R.hsb2rgb = function (h, s, v, o) {
+        if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) {
+            v = h.b;
+            s = h.s;
+            o = h.o;
+            h = h.h;
+        }
+        h *= 360;
+        var R, G, B, X, C;
+        h = (h % 360) / 60;
+        C = v * s;
+        X = C * (1 - abs(h % 2 - 1));
+        R = G = B = v - C;
+
+        h = ~~h;
+        R += [C, X, 0, 0, X, C][h];
+        G += [X, C, C, X, 0, 0][h];
+        B += [0, 0, X, C, C, X][h];
+        return packageRGB(R, G, B, o);
+    };
+    /*\
+     * Raphael.hsl2rgb
+     [ method ]
+     **
+     * Converts HSL values to RGB object.
+     > Parameters
+     - h (number) hue
+     - s (number) saturation
+     - l (number) luminosity
+     = (object) RGB object in format:
+     o {
+     o     r (number) red,
+     o     g (number) green,
+     o     b (number) blue,
+     o     hex (string) color in HTML/CSS format: #••••••
+     o }
+     \*/
+    R.hsl2rgb = function (h, s, l, o) {
+        if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) {
+            l = h.l;
+            s = h.s;
+            h = h.h;
+        }
+        if (h > 1 || s > 1 || l > 1) {
+            h /= 360;
+            s /= 100;
+            l /= 100;
+        }
+        h *= 360;
+        var R, G, B, X, C;
+        h = (h % 360) / 60;
+        C = 2 * s * (l < .5 ? l : 1 - l);
+        X = C * (1 - abs(h % 2 - 1));
+        R = G = B = l - C / 2;
+
+        h = ~~h;
+        R += [C, X, 0, 0, X, C][h];
+        G += [X, C, C, X, 0, 0][h];
+        B += [0, 0, X, C, C, X][h];
+        return packageRGB(R, G, B, o);
+    };
+    /*\
+     * Raphael.rgb2hsb
+     [ method ]
+     **
+     * Converts RGB values to HSB object.
+     > Parameters
+     - r (number) red
+     - g (number) green
+     - b (number) blue
+     = (object) HSB object in format:
+     o {
+     o     h (number) hue
+     o     s (number) saturation
+     o     b (number) brightness
+     o }
+     \*/
+    R.rgb2hsb = function (r, g, b) {
+        b = prepareRGB(r, g, b);
+        r = b[0];
+        g = b[1];
+        b = b[2];
+
+        var H, S, V, C;
+        V = mmax(r, g, b);
+        C = V - mmin(r, g, b);
+        H = (C == 0 ? null :
+                V == r ? (g - b) / C :
+                    V == g ? (b - r) / C + 2 :
+                    (r - g) / C + 4
+        );
+        H = ((H + 360) % 6) * 60 / 360;
+        S = C == 0 ? 0 : C / V;
+        return {h: H, s: S, b: V, toString: hsbtoString};
+    };
+    /*\
+     * Raphael.rgb2hsl
+     [ method ]
+     **
+     * Converts RGB values to HSL object.
+     > Parameters
+     - r (number) red
+     - g (number) green
+     - b (number) blue
+     = (object) HSL object in format:
+     o {
+     o     h (number) hue
+     o     s (number) saturation
+     o     l (number) luminosity
+     o }
+     \*/
+    R.rgb2hsl = function (r, g, b) {
+        b = prepareRGB(r, g, b);
+        r = b[0];
+        g = b[1];
+        b = b[2];
+
+        var H, S, L, M, m, C;
+        M = mmax(r, g, b);
+        m = mmin(r, g, b);
+        C = M - m;
+        H = (C == 0 ? null :
+            M == r ? (g - b) / C :
+                M == g ? (b - r) / C + 2 :
+                (r - g) / C + 4);
+        H = ((H + 360) % 6) * 60 / 360;
+        L = (M + m) / 2;
+        S = (C == 0 ? 0 :
+            L < .5 ? C / (2 * L) :
+            C / (2 - 2 * L));
+        return {h: H, s: S, l: L, toString: hsltoString};
+    };
+    R._path2string = function () {
+        return this.join(",").replace(p2s, "$1");
+    };
+    function repush(array, item) {
+        for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
+            return array.push(array.splice(i, 1)[0]);
+        }
+    }
+    function cacher(f, scope, postprocessor) {
+        function newf() {
+            var arg = Array.prototype.slice.call(arguments, 0),
+                args = arg.join("\u2400"),
+                cache = newf.cache = newf.cache || {},
+                count = newf.count = newf.count || [];
+            if (cache[has](args)) {
+                repush(count, args);
+                return postprocessor ? postprocessor(cache[args]) : cache[args];
+            }
+            count.length >= 1e3 && delete cache[count.shift()];
+            count.push(args);
+            cache[args] = f[apply](scope, arg);
+            return postprocessor ? postprocessor(cache[args]) : cache[args];
+        }
+        return newf;
+    }
+
+    var preload = R._preload = function (src, f) {
+        var img = g.doc.createElement("img");
+        img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
+        img.onload = function () {
+            f.call(this);
+            this.onload = null;
+            g.doc.body.removeChild(this);
+        };
+        img.onerror = function () {
+            g.doc.body.removeChild(this);
+        };
+        g.doc.body.appendChild(img);
+        img.src = src;
+    };
+
+    function clrToString() {
+        return this.hex;
+    }
+
+    /*\
+     * Raphael.getRGB
+     [ method ]
+     **
+     * Parses colour string as RGB object
+     > Parameters
+     - colour (string) colour string in one of formats:
+     # <ul>
+     #     <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li>
+     #     <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li>
+     #     <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li>
+     #     <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200,&nbsp;100,&nbsp;0)</code>”)</li>
+     #     <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%,&nbsp;175%,&nbsp;0%)</code>”)</li>
+     #     <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5,&nbsp;0.25,&nbsp;1)</code>”)</li>
+     #     <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
+     #     <li>hsl(•••, •••, •••) — same as hsb</li>
+     #     <li>hsl(•••%, •••%, •••%) — same as hsb</li>
+     # </ul>
+     = (object) RGB object in format:
+     o {
+     o     r (number) red,
+     o     g (number) green,
+     o     b (number) blue
+     o     hex (string) color in HTML/CSS format: #••••••,
+     o     error (boolean) true if string can’t be parsed
+     o }
+     \*/
+    R.getRGB = cacher(function (colour) {
+        if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
+            return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString};
+        }
+        if (colour == "none") {
+            return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString};
+        }
+        !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
+        var res,
+            red,
+            green,
+            blue,
+            opacity,
+            t,
+            values,
+            rgb = colour.match(colourRegExp);
+        if (rgb) {
+            if (rgb[2]) {
+                blue = toInt(rgb[2].substring(5), 16);
+                green = toInt(rgb[2].substring(3, 5), 16);
+                red = toInt(rgb[2].substring(1, 3), 16);
+            }
+            if (rgb[3]) {
+                blue = toInt((t = rgb[3].charAt(3)) + t, 16);
+                green = toInt((t = rgb[3].charAt(2)) + t, 16);
+                red = toInt((t = rgb[3].charAt(1)) + t, 16);
+            }
+            if (rgb[4]) {
+                values = rgb[4][split](commaSpaces);
+                red = toFloat(values[0]);
+                values[0].slice(-1) == "%" && (red *= 2.55);
+                green = toFloat(values[1]);
+                values[1].slice(-1) == "%" && (green *= 2.55);
+                blue = toFloat(values[2]);
+                values[2].slice(-1) == "%" && (blue *= 2.55);
+                rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
+                values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+            }
+            if (rgb[5]) {
+                values = rgb[5][split](commaSpaces);
+                red = toFloat(values[0]);
+                values[0].slice(-1) == "%" && (red *= 2.55);
+                green = toFloat(values[1]);
+                values[1].slice(-1) == "%" && (green *= 2.55);
+                blue = toFloat(values[2]);
+                values[2].slice(-1) == "%" && (blue *= 2.55);
+                (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+                rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
+                values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+                return R.hsb2rgb(red, green, blue, opacity);
+            }
+            if (rgb[6]) {
+                values = rgb[6][split](commaSpaces);
+                red = toFloat(values[0]);
+                values[0].slice(-1) == "%" && (red *= 2.55);
+                green = toFloat(values[1]);
+                values[1].slice(-1) == "%" && (green *= 2.55);
+                blue = toFloat(values[2]);
+                values[2].slice(-1) == "%" && (blue *= 2.55);
+                (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+                rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
+                values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+                return R.hsl2rgb(red, green, blue, opacity);
+            }
+            rgb = {r: red, g: green, b: blue, toString: clrToString};
+            rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
+            R.is(opacity, "finite") && (rgb.opacity = opacity);
+            return rgb;
+        }
+        return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString};
+    }, R);
+    /*\
+     * Raphael.hsb
+     [ method ]
+     **
+     * Converts HSB values to hex representation of the colour.
+     > Parameters
+     - h (number) hue
+     - s (number) saturation
+     - b (number) value or brightness
+     = (string) hex representation of the colour.
+     \*/
+    R.hsb = cacher(function (h, s, b) {
+        return R.hsb2rgb(h, s, b).hex;
+    });
+    /*\
+     * Raphael.hsl
+     [ method ]
+     **
+     * Converts HSL values to hex representation of the colour.
+     > Parameters
+     - h (number) hue
+     - s (number) saturation
+     - l (number) luminosity
+     = (string) hex representation of the colour.
+     \*/
+    R.hsl = cacher(function (h, s, l) {
+        return R.hsl2rgb(h, s, l).hex;
+    });
+    /*\
+     * Raphael.rgb
+     [ method ]
+     **
+     * Converts RGB values to hex representation of the colour.
+     > Parameters
+     - r (number) red
+     - g (number) green
+     - b (number) blue
+     = (string) hex representation of the colour.
+     \*/
+    R.rgb = cacher(function (r, g, b) {
+        function round(x) { return (x + 0.5) | 0; }
+        return "#" + (16777216 | round(b) | (round(g) << 8) | (round(r) << 16)).toString(16).slice(1);
+    });
+    /*\
+     * Raphael.getColor
+     [ method ]
+     **
+     * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset
+     > Parameters
+     - value (number) #optional brightness, default is `0.75`
+     = (string) hex representation of the colour.
+     \*/
+    R.getColor = function (value) {
+        var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75},
+            rgb = this.hsb2rgb(start.h, start.s, start.b);
+        start.h += .075;
+        if (start.h > 1) {
+            start.h = 0;
+            start.s -= .2;
+            start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b});
+        }
+        return rgb.hex;
+    };
+    /*\
+     * Raphael.getColor.reset
+     [ method ]
+     **
+     * Resets spectrum position for @Raphael.getColor back to red.
+     \*/
+    R.getColor.reset = function () {
+        delete this.start;
+    };
+
+    // http://schepers.cc/getting-to-the-point
+    function catmullRom2bezier(crp, z) {
+        var d = [];
+        for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
+            var p = [
+                {x: +crp[i - 2], y: +crp[i - 1]},
+                {x: +crp[i],     y: +crp[i + 1]},
+                {x: +crp[i + 2], y: +crp[i + 3]},
+                {x: +crp[i + 4], y: +crp[i + 5]}
+            ];
+            if (z) {
+                if (!i) {
+                    p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
+                } else if (iLen - 4 == i) {
+                    p[3] = {x: +crp[0], y: +crp[1]};
+                } else if (iLen - 2 == i) {
+                    p[2] = {x: +crp[0], y: +crp[1]};
+                    p[3] = {x: +crp[2], y: +crp[3]};
+                }
+            } else {
+                if (iLen - 4 == i) {
+                    p[3] = p[2];
+                } else if (!i) {
+                    p[0] = {x: +crp[i], y: +crp[i + 1]};
+                }
+            }
+            d.push(["C",
+                (-p[0].x + 6 * p[1].x + p[2].x) / 6,
+                (-p[0].y + 6 * p[1].y + p[2].y) / 6,
+                (p[1].x + 6 * p[2].x - p[3].x) / 6,
+                (p[1].y + 6*p[2].y - p[3].y) / 6,
+                p[2].x,
+                p[2].y
+            ]);
+        }
+
+        return d;
+    }
+    /*\
+     * Raphael.parsePathString
+     [ method ]
+     **
+     * Utility method
+     **
+     * Parses given path string into an array of arrays of path segments.
+     > Parameters
+     - pathString (string|array) path string or array of segments (in the last case it will be returned straight away)
+     = (array) array of segments.
+     \*/
+    R.parsePathString = function (pathString) {
+        if (!pathString) {
+            return null;
+        }
+        var pth = paths(pathString);
+        if (pth.arr) {
+            return pathClone(pth.arr);
+        }
+
+        var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0},
+            data = [];
+        if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption
+            data = pathClone(pathString);
+        }
+        if (!data.length) {
+            Str(pathString).replace(pathCommand, function (a, b, c) {
+                var params = [],
+                    name = b.toLowerCase();
+                c.replace(pathValues, function (a, b) {
+                    b && params.push(+b);
+                });
+                if (name == "m" && params.length > 2) {
+                    data.push([b][concat](params.splice(0, 2)));
+                    name = "l";
+                    b = b == "m" ? "l" : "L";
+                }
+                if (name == "r") {
+                    data.push([b][concat](params));
+                } else while (params.length >= paramCounts[name]) {
+                    data.push([b][concat](params.splice(0, paramCounts[name])));
+                    if (!paramCounts[name]) {
+                        break;
+                    }
+                }
+            });
+        }
+        data.toString = R._path2string;
+        pth.arr = pathClone(data);
+        return data;
+    };
+    /*\
+     * Raphael.parseTransformString
+     [ method ]
+     **
+     * Utility method
+     **
+     * Parses given path string into an array of transformations.
+     > Parameters
+     - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away)
+     = (array) array of transformations.
+     \*/
+    R.parseTransformString = cacher(function (TString) {
+        if (!TString) {
+            return null;
+        }
+        var paramCounts = {r: 3, s: 4, t: 2, m: 6},
+            data = [];
+        if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption
+            data = pathClone(TString);
+        }
+        if (!data.length) {
+            Str(TString).replace(tCommand, function (a, b, c) {
+                var params = [],
+                    name = lowerCase.call(b);
+                c.replace(pathValues, function (a, b) {
+                    b && params.push(+b);
+                });
+                data.push([b][concat](params));
+            });
+        }
+        data.toString = R._path2string;
+        return data;
+    });
+    // PATHS
+    var paths = function (ps) {
+        var p = paths.ps = paths.ps || {};
+        if (p[ps]) {
+            p[ps].sleep = 100;
+        } else {
+            p[ps] = {
+                sleep: 100
+            };
+        }
+        setTimeout(function () {
+            for (var key in p) if (p[has](key) && key != ps) {
+                p[key].sleep--;
+                !p[key].sleep && delete p[key];
+            }
+        });
+        return p[ps];
+    };
+    /*\
+     * Raphael.findDotsAtSegment
+     [ method ]
+     **
+     * Utility method
+     **
+     * Find dot coordinates on the given cubic bezier curve at the given t.
+     > Parameters
+     - p1x (number) x of the first point of the curve
+     - p1y (number) y of the first point of the curve
+     - c1x (number) x of the first anchor of the curve
+     - c1y (number) y of the first anchor of the curve
+     - c2x (number) x of the second anchor of the curve
+     - c2y (number) y of the second anchor of the curve
+     - p2x (number) x of the second point of the curve
+     - p2y (number) y of the second point of the curve
+     - t (number) position on the curve (0..1)
+     = (object) point information in format:
+     o {
+     o     x: (number) x coordinate of the point
+     o     y: (number) y coordinate of the point
+     o     m: {
+     o         x: (number) x coordinate of the left anchor
+     o         y: (number) y coordinate of the left anchor
+     o     }
+     o     n: {
+     o         x: (number) x coordinate of the right anchor
+     o         y: (number) y coordinate of the right anchor
+     o     }
+     o     start: {
+     o         x: (number) x coordinate of the start of the curve
+     o         y: (number) y coordinate of the start of the curve
+     o     }
+     o     end: {
+     o         x: (number) x coordinate of the end of the curve
+     o         y: (number) y coordinate of the end of the curve
+     o     }
+     o     alpha: (number) angle of the curve derivative at the point
+     o }
+     \*/
+    R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+        var t1 = 1 - t,
+            t13 = pow(t1, 3),
+            t12 = pow(t1, 2),
+            t2 = t * t,
+            t3 = t2 * t,
+            x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
+            y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
+            mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
+            my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
+            nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
+            ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
+            ax = t1 * p1x + t * c1x,
+            ay = t1 * p1y + t * c1y,
+            cx = t1 * c2x + t * p2x,
+            cy = t1 * c2y + t * p2y,
+            alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
+        (mx > nx || my < ny) && (alpha += 180);
+        return {
+            x: x,
+            y: y,
+            m: {x: mx, y: my},
+            n: {x: nx, y: ny},
+            start: {x: ax, y: ay},
+            end: {x: cx, y: cy},
+            alpha: alpha
+        };
+    };
+    /*\
+     * Raphael.bezierBBox
+     [ method ]
+     **
+     * Utility method
+     **
+     * Return bounding box of a given cubic bezier curve
+     > Parameters
+     - p1x (number) x of the first point of the curve
+     - p1y (number) y of the first point of the curve
+     - c1x (number) x of the first anchor of the curve
+     - c1y (number) y of the first anchor of the curve
+     - c2x (number) x of the second anchor of the curve
+     - c2y (number) y of the second anchor of the curve
+     - p2x (number) x of the second point of the curve
+     - p2y (number) y of the second point of the curve
+     * or
+     - bez (array) array of six points for bezier curve
+     = (object) point information in format:
+     o {
+     o     min: {
+     o         x: (number) x coordinate of the left point
+     o         y: (number) y coordinate of the top point
+     o     }
+     o     max: {
+     o         x: (number) x coordinate of the right point
+     o         y: (number) y coordinate of the bottom point
+     o     }
+     o }
+     \*/
+    R.bezierBBox = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+        if (!R.is(p1x, "array")) {
+            p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
+        }
+        var bbox = curveDim.apply(null, p1x);
+        return {
+            x: bbox.min.x,
+            y: bbox.min.y,
+            x2: bbox.max.x,
+            y2: bbox.max.y,
+            width: bbox.max.x - bbox.min.x,
+            height: bbox.max.y - bbox.min.y
+        };
+    };
+    /*\
+     * Raphael.isPointInsideBBox
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns `true` if given point is inside bounding boxes.
+     > Parameters
+     - bbox (string) bounding box
+     - x (string) x coordinate of the point
+     - y (string) y coordinate of the point
+     = (boolean) `true` if point inside
+     \*/
+    R.isPointInsideBBox = function (bbox, x, y) {
+        return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2;
+    };
+    /*\
+     * Raphael.isBBoxIntersect
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns `true` if two bounding boxes intersect
+     > Parameters
+     - bbox1 (string) first bounding box
+     - bbox2 (string) second bounding box
+     = (boolean) `true` if they intersect
+     \*/
+    R.isBBoxIntersect = function (bbox1, bbox2) {
+        var i = R.isPointInsideBBox;
+        return i(bbox2, bbox1.x, bbox1.y)
+            || i(bbox2, bbox1.x2, bbox1.y)
+            || i(bbox2, bbox1.x, bbox1.y2)
+            || i(bbox2, bbox1.x2, bbox1.y2)
+            || i(bbox1, bbox2.x, bbox2.y)
+            || i(bbox1, bbox2.x2, bbox2.y)
+            || i(bbox1, bbox2.x, bbox2.y2)
+            || i(bbox1, bbox2.x2, bbox2.y2)
+            || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
+            && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
+    };
+    function base3(t, p1, p2, p3, p4) {
+        var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
+            t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
+        return t * t2 - 3 * p1 + 3 * p2;
+    }
+    function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
+        if (z == null) {
+            z = 1;
+        }
+        z = z > 1 ? 1 : z < 0 ? 0 : z;
+        var z2 = z / 2,
+            n = 12,
+            Tvalues = [-0.1252,0.1252,-0.3678,0.3678,-0.5873,0.5873,-0.7699,0.7699,-0.9041,0.9041,-0.9816,0.9816],
+            Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472],
+            sum = 0;
+        for (var i = 0; i < n; i++) {
+            var ct = z2 * Tvalues[i] + z2,
+                xbase = base3(ct, x1, x2, x3, x4),
+                ybase = base3(ct, y1, y2, y3, y4),
+                comb = xbase * xbase + ybase * ybase;
+            sum += Cvalues[i] * math.sqrt(comb);
+        }
+        return z2 * sum;
+    }
+    function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
+        if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
+            return;
+        }
+        var t = 1,
+            step = t / 2,
+            t2 = t - step,
+            l,
+            e = .01;
+        l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+        while (abs(l - ll) > e) {
+            step /= 2;
+            t2 += (l < ll ? 1 : -1) * step;
+            l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+        }
+        return t2;
+    }
+    function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
+        if (
+            mmax(x1, x2) < mmin(x3, x4) ||
+            mmin(x1, x2) > mmax(x3, x4) ||
+            mmax(y1, y2) < mmin(y3, y4) ||
+            mmin(y1, y2) > mmax(y3, y4)
+        ) {
+            return;
+        }
+        var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
+            ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
+            denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+
+        if (!denominator) {
+            return;
+        }
+        var px = nx / denominator,
+            py = ny / denominator,
+            px2 = +px.toFixed(2),
+            py2 = +py.toFixed(2);
+        if (
+            px2 < +mmin(x1, x2).toFixed(2) ||
+            px2 > +mmax(x1, x2).toFixed(2) ||
+            px2 < +mmin(x3, x4).toFixed(2) ||
+            px2 > +mmax(x3, x4).toFixed(2) ||
+            py2 < +mmin(y1, y2).toFixed(2) ||
+            py2 > +mmax(y1, y2).toFixed(2) ||
+            py2 < +mmin(y3, y4).toFixed(2) ||
+            py2 > +mmax(y3, y4).toFixed(2)
+        ) {
+            return;
+        }
+        return {x: px, y: py};
+    }
+    function inter(bez1, bez2) {
+        return interHelper(bez1, bez2);
+    }
+    function interCount(bez1, bez2) {
+        return interHelper(bez1, bez2, 1);
+    }
+    function interHelper(bez1, bez2, justCount) {
+        var bbox1 = R.bezierBBox(bez1),
+            bbox2 = R.bezierBBox(bez2);
+        if (!R.isBBoxIntersect(bbox1, bbox2)) {
+            return justCount ? 0 : [];
+        }
+        var l1 = bezlen.apply(0, bez1),
+            l2 = bezlen.apply(0, bez2),
+            n1 = mmax(~~(l1 / 5), 1),
+            n2 = mmax(~~(l2 / 5), 1),
+            dots1 = [],
+            dots2 = [],
+            xy = {},
+            res = justCount ? 0 : [];
+        for (var i = 0; i < n1 + 1; i++) {
+            var p = R.findDotsAtSegment.apply(R, bez1.concat(i / n1));
+            dots1.push({x: p.x, y: p.y, t: i / n1});
+        }
+        for (i = 0; i < n2 + 1; i++) {
+            p = R.findDotsAtSegment.apply(R, bez2.concat(i / n2));
+            dots2.push({x: p.x, y: p.y, t: i / n2});
+        }
+        for (i = 0; i < n1; i++) {
+            for (var j = 0; j < n2; j++) {
+                var di = dots1[i],
+                    di1 = dots1[i + 1],
+                    dj = dots2[j],
+                    dj1 = dots2[j + 1],
+                    ci = abs(di1.x - di.x) < .001 ? "y" : "x",
+                    cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
+                    is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
+                if (is) {
+                    if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
+                        continue;
+                    }
+                    xy[is.x.toFixed(4)] = is.y.toFixed(4);
+                    var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
+                        t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
+                    if (t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001) {
+                        if (justCount) {
+                            res++;
+                        } else {
+                            res.push({
+                                x: is.x,
+                                y: is.y,
+                                t1: mmin(t1, 1),
+                                t2: mmin(t2, 1)
+                            });
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+    /*\
+     * Raphael.pathIntersection
+     [ method ]
+     **
+     * Utility method
+     **
+     * Finds intersections of two paths
+     > Parameters
+     - path1 (string) path string
+     - path2 (string) path string
+     = (array) dots of intersection
+     o [
+     o     {
+     o         x: (number) x coordinate of the point
+     o         y: (number) y coordinate of the point
+     o         t1: (number) t value for segment of path1
+     o         t2: (number) t value for segment of path2
+     o         segment1: (number) order number for segment of path1
+     o         segment2: (number) order number for segment of path2
+     o         bez1: (array) eight coordinates representing beziér curve for the segment of path1
+     o         bez2: (array) eight coordinates representing beziér curve for the segment of path2
+     o     }
+     o ]
+     \*/
+    R.pathIntersection = function (path1, path2) {
+        return interPathHelper(path1, path2);
+    };
+    R.pathIntersectionNumber = function (path1, path2) {
+        return interPathHelper(path1, path2, 1);
+    };
+    function interPathHelper(path1, path2, justCount) {
+        path1 = R._path2curve(path1);
+        path2 = R._path2curve(path2);
+        var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
+            res = justCount ? 0 : [];
+        for (var i = 0, ii = path1.length; i < ii; i++) {
+            var pi = path1[i];
+            if (pi[0] == "M") {
+                x1 = x1m = pi[1];
+                y1 = y1m = pi[2];
+            } else {
+                if (pi[0] == "C") {
+                    bez1 = [x1, y1].concat(pi.slice(1));
+                    x1 = bez1[6];
+                    y1 = bez1[7];
+                } else {
+                    bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
+                    x1 = x1m;
+                    y1 = y1m;
+                }
+                for (var j = 0, jj = path2.length; j < jj; j++) {
+                    var pj = path2[j];
+                    if (pj[0] == "M") {
+                        x2 = x2m = pj[1];
+                        y2 = y2m = pj[2];
+                    } else {
+                        if (pj[0] == "C") {
+                            bez2 = [x2, y2].concat(pj.slice(1));
+                            x2 = bez2[6];
+                            y2 = bez2[7];
+                        } else {
+                            bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
+                            x2 = x2m;
+                            y2 = y2m;
+                        }
+                        var intr = interHelper(bez1, bez2, justCount);
+                        if (justCount) {
+                            res += intr;
+                        } else {
+                            for (var k = 0, kk = intr.length; k < kk; k++) {
+                                intr[k].segment1 = i;
+                                intr[k].segment2 = j;
+                                intr[k].bez1 = bez1;
+                                intr[k].bez2 = bez2;
+                            }
+                            res = res.concat(intr);
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+    /*\
+     * Raphael.isPointInsidePath
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns `true` if given point is inside a given closed path.
+     > Parameters
+     - path (string) path string
+     - x (number) x of the point
+     - y (number) y of the point
+     = (boolean) true, if point is inside the path
+     \*/
+    R.isPointInsidePath = function (path, x, y) {
+        var bbox = R.pathBBox(path);
+        return R.isPointInsideBBox(bbox, x, y) &&
+            interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1;
+    };
+    R._removedFactory = function (methodname) {
+        return function () {
+            eve("raphael.log", null, "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object", methodname);
+        };
+    };
+    /*\
+     * Raphael.pathBBox
+     [ method ]
+     **
+     * Utility method
+     **
+     * Return bounding box of a given path
+     > Parameters
+     - path (string) path string
+     = (object) bounding box
+     o {
+     o     x: (number) x coordinate of the left top point of the box
+     o     y: (number) y coordinate of the left top point of the box
+     o     x2: (number) x coordinate of the right bottom point of the box
+     o     y2: (number) y coordinate of the right bottom point of the box
+     o     width: (number) width of the box
+     o     height: (number) height of the box
+     o     cx: (number) x coordinate of the center of the box
+     o     cy: (number) y coordinate of the center of the box
+     o }
+     \*/
+    var pathDimensions = R.pathBBox = function (path) {
+            var pth = paths(path);
+            if (pth.bbox) {
+                return clone(pth.bbox);
+            }
+            if (!path) {
+                return {x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0};
+            }
+            path = path2curve(path);
+            var x = 0,
+                y = 0,
+                X = [],
+                Y = [],
+                p;
+            for (var i = 0, ii = path.length; i < ii; i++) {
+                p = path[i];
+                if (p[0] == "M") {
+                    x = p[1];
+                    y = p[2];
+                    X.push(x);
+                    Y.push(y);
+                } else {
+                    var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+                    X = X[concat](dim.min.x, dim.max.x);
+                    Y = Y[concat](dim.min.y, dim.max.y);
+                    x = p[5];
+                    y = p[6];
+                }
+            }
+            var xmin = mmin[apply](0, X),
+                ymin = mmin[apply](0, Y),
+                xmax = mmax[apply](0, X),
+                ymax = mmax[apply](0, Y),
+                width = xmax - xmin,
+                height = ymax - ymin,
+                bb = {
+                    x: xmin,
+                    y: ymin,
+                    x2: xmax,
+                    y2: ymax,
+                    width: width,
+                    height: height,
+                    cx: xmin + width / 2,
+                    cy: ymin + height / 2
+                };
+            pth.bbox = clone(bb);
+            return bb;
+        },
+        pathClone = function (pathArray) {
+            var res = clone(pathArray);
+            res.toString = R._path2string;
+            return res;
+        },
+        pathToRelative = R._pathToRelative = function (pathArray) {
+            var pth = paths(pathArray);
+            if (pth.rel) {
+                return pathClone(pth.rel);
+            }
+            if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+                pathArray = R.parsePathString(pathArray);
+            }
+            var res = [],
+                x = 0,
+                y = 0,
+                mx = 0,
+                my = 0,
+                start = 0;
+            if (pathArray[0][0] == "M") {
+                x = pathArray[0][1];
+                y = pathArray[0][2];
+                mx = x;
+                my = y;
+                start++;
+                res.push(["M", x, y]);
+            }
+            for (var i = start, ii = pathArray.length; i < ii; i++) {
+                var r = res[i] = [],
+                    pa = pathArray[i];
+                if (pa[0] != lowerCase.call(pa[0])) {
+                    r[0] = lowerCase.call(pa[0]);
+                    switch (r[0]) {
+                        case "a":
+                            r[1] = pa[1];
+                            r[2] = pa[2];
+                            r[3] = pa[3];
+                            r[4] = pa[4];
+                            r[5] = pa[5];
+                            r[6] = +(pa[6] - x).toFixed(3);
+                            r[7] = +(pa[7] - y).toFixed(3);
+                            break;
+                        case "v":
+                            r[1] = +(pa[1] - y).toFixed(3);
+                            break;
+                        case "m":
+                            mx = pa[1];
+                            my = pa[2];
+                        default:
+                            for (var j = 1, jj = pa.length; j < jj; j++) {
+                                r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
+                            }
+                    }
+                } else {
+                    r = res[i] = [];
+                    if (pa[0] == "m") {
+                        mx = pa[1] + x;
+                        my = pa[2] + y;
+                    }
+                    for (var k = 0, kk = pa.length; k < kk; k++) {
+                        res[i][k] = pa[k];
+                    }
+                }
+                var len = res[i].length;
+                switch (res[i][0]) {
+                    case "z":
+                        x = mx;
+                        y = my;
+                        break;
+                    case "h":
+                        x += +res[i][len - 1];
+                        break;
+                    case "v":
+                        y += +res[i][len - 1];
+                        break;
+                    default:
+                        x += +res[i][len - 2];
+                        y += +res[i][len - 1];
+                }
+            }
+            res.toString = R._path2string;
+            pth.rel = pathClone(res);
+            return res;
+        },
+        pathToAbsolute = R._pathToAbsolute = function (pathArray) {
+            var pth = paths(pathArray);
+            if (pth.abs) {
+                return pathClone(pth.abs);
+            }
+            if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
+                pathArray = R.parsePathString(pathArray);
+            }
+            if (!pathArray || !pathArray.length) {
+                return [["M", 0, 0]];
+            }
+            var res = [],
+                x = 0,
+                y = 0,
+                mx = 0,
+                my = 0,
+                start = 0;
+            if (pathArray[0][0] == "M") {
+                x = +pathArray[0][1];
+                y = +pathArray[0][2];
+                mx = x;
+                my = y;
+                start++;
+                res[0] = ["M", x, y];
+            }
+            var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z";
+            for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
+                res.push(r = []);
+                pa = pathArray[i];
+                if (pa[0] != upperCase.call(pa[0])) {
+                    r[0] = upperCase.call(pa[0]);
+                    switch (r[0]) {
+                        case "A":
+                            r[1] = pa[1];
+                            r[2] = pa[2];
+                            r[3] = pa[3];
+                            r[4] = pa[4];
+                            r[5] = pa[5];
+                            r[6] = +(pa[6] + x);
+                            r[7] = +(pa[7] + y);
+                            break;
+                        case "V":
+                            r[1] = +pa[1] + y;
+                            break;
+                        case "H":
+                            r[1] = +pa[1] + x;
+                            break;
+                        case "R":
+                            var dots = [x, y][concat](pa.slice(1));
+                            for (var j = 2, jj = dots.length; j < jj; j++) {
+                                dots[j] = +dots[j] + x;
+                                dots[++j] = +dots[j] + y;
+                            }
+                            res.pop();
+                            res = res[concat](catmullRom2bezier(dots, crz));
+                            break;
+                        case "M":
+                            mx = +pa[1] + x;
+                            my = +pa[2] + y;
+                        default:
+                            for (j = 1, jj = pa.length; j < jj; j++) {
+                                r[j] = +pa[j] + ((j % 2) ? x : y);
+                            }
+                    }
+                } else if (pa[0] == "R") {
+                    dots = [x, y][concat](pa.slice(1));
+                    res.pop();
+                    res = res[concat](catmullRom2bezier(dots, crz));
+                    r = ["R"][concat](pa.slice(-2));
+                } else {
+                    for (var k = 0, kk = pa.length; k < kk; k++) {
+                        r[k] = pa[k];
+                    }
+                }
+                switch (r[0]) {
+                    case "Z":
+                        x = mx;
+                        y = my;
+                        break;
+                    case "H":
+                        x = r[1];
+                        break;
+                    case "V":
+                        y = r[1];
+                        break;
+                    case "M":
+                        mx = r[r.length - 2];
+                        my = r[r.length - 1];
+                    default:
+                        x = r[r.length - 2];
+                        y = r[r.length - 1];
+                }
+            }
+            res.toString = R._path2string;
+            pth.abs = pathClone(res);
+            return res;
+        },
+        l2c = function (x1, y1, x2, y2) {
+            return [x1, y1, x2, y2, x2, y2];
+        },
+        q2c = function (x1, y1, ax, ay, x2, y2) {
+            var _13 = 1 / 3,
+                _23 = 2 / 3;
+            return [
+                _13 * x1 + _23 * ax,
+                _13 * y1 + _23 * ay,
+                _13 * x2 + _23 * ax,
+                _13 * y2 + _23 * ay,
+                x2,
+                y2
+            ];
+        },
+        a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+            // for more information of where this math came from visit:
+            // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+            var _120 = PI * 120 / 180,
+                rad = PI / 180 * (+angle || 0),
+                res = [],
+                xy,
+                rotate = cacher(function (x, y, rad) {
+                    var X = x * math.cos(rad) - y * math.sin(rad),
+                        Y = x * math.sin(rad) + y * math.cos(rad);
+                    return {x: X, y: Y};
+                });
+            if (!recursive) {
+                xy = rotate(x1, y1, -rad);
+                x1 = xy.x;
+                y1 = xy.y;
+                xy = rotate(x2, y2, -rad);
+                x2 = xy.x;
+                y2 = xy.y;
+                var cos = math.cos(PI / 180 * angle),
+                    sin = math.sin(PI / 180 * angle),
+                    x = (x1 - x2) / 2,
+                    y = (y1 - y2) / 2;
+                var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+                if (h > 1) {
+                    h = math.sqrt(h);
+                    rx = h * rx;
+                    ry = h * ry;
+                }
+                var rx2 = rx * rx,
+                    ry2 = ry * ry,
+                    k = (large_arc_flag == sweep_flag ? -1 : 1) *
+                        math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+                    cx = k * rx * y / ry + (x1 + x2) / 2,
+                    cy = k * -ry * x / rx + (y1 + y2) / 2,
+                    f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
+                    f2 = math.asin(((y2 - cy) / ry).toFixed(9));
+
+                f1 = x1 < cx ? PI - f1 : f1;
+                f2 = x2 < cx ? PI - f2 : f2;
+                f1 < 0 && (f1 = PI * 2 + f1);
+                f2 < 0 && (f2 = PI * 2 + f2);
+                if (sweep_flag && f1 > f2) {
+                    f1 = f1 - PI * 2;
+                }
+                if (!sweep_flag && f2 > f1) {
+                    f2 = f2 - PI * 2;
+                }
+            } else {
+                f1 = recursive[0];
+                f2 = recursive[1];
+                cx = recursive[2];
+                cy = recursive[3];
+            }
+            var df = f2 - f1;
+            if (abs(df) > _120) {
+                var f2old = f2,
+                    x2old = x2,
+                    y2old = y2;
+                f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+                x2 = cx + rx * math.cos(f2);
+                y2 = cy + ry * math.sin(f2);
+                res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+            }
+            df = f2 - f1;
+            var c1 = math.cos(f1),
+                s1 = math.sin(f1),
+                c2 = math.cos(f2),
+                s2 = math.sin(f2),
+                t = math.tan(df / 4),
+                hx = 4 / 3 * rx * t,
+                hy = 4 / 3 * ry * t,
+                m1 = [x1, y1],
+                m2 = [x1 + hx * s1, y1 - hy * c1],
+                m3 = [x2 + hx * s2, y2 - hy * c2],
+                m4 = [x2, y2];
+            m2[0] = 2 * m1[0] - m2[0];
+            m2[1] = 2 * m1[1] - m2[1];
+            if (recursive) {
+                return [m2, m3, m4][concat](res);
+            } else {
+                res = [m2, m3, m4][concat](res).join()[split](",");
+                var newres = [];
+                for (var i = 0, ii = res.length; i < ii; i++) {
+                    newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
+                }
+                return newres;
+            }
+        },
+        findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+            var t1 = 1 - t;
+            return {
+                x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
+                y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
+            };
+        },
+        curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+            var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
+                b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
+                c = p1x - c1x,
+                t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
+                t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
+                y = [p1y, p2y],
+                x = [p1x, p2x],
+                dot;
+            abs(t1) > "1e12" && (t1 = .5);
+            abs(t2) > "1e12" && (t2 = .5);
+            if (t1 > 0 && t1 < 1) {
+                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+                x.push(dot.x);
+                y.push(dot.y);
+            }
+            if (t2 > 0 && t2 < 1) {
+                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+                x.push(dot.x);
+                y.push(dot.y);
+            }
+            a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
+            b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
+            c = p1y - c1y;
+            t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
+            t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
+            abs(t1) > "1e12" && (t1 = .5);
+            abs(t2) > "1e12" && (t2 = .5);
+            if (t1 > 0 && t1 < 1) {
+                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+                x.push(dot.x);
+                y.push(dot.y);
+            }
+            if (t2 > 0 && t2 < 1) {
+                dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+                x.push(dot.x);
+                y.push(dot.y);
+            }
+            return {
+                min: {x: mmin[apply](0, x), y: mmin[apply](0, y)},
+                max: {x: mmax[apply](0, x), y: mmax[apply](0, y)}
+            };
+        }),
+        path2curve = R._path2curve = cacher(function (path, path2) {
+            var pth = !path2 && paths(path);
+            if (!path2 && pth.curve) {
+                return pathClone(pth.curve);
+            }
+            var p = pathToAbsolute(path),
+                p2 = path2 && pathToAbsolute(path2),
+                attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+                attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+                processPath = function (path, d, pcom) {
+                    var nx, ny, tq = {T:1, Q:1};
+                    if (!path) {
+                        return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
+                    }
+                    !(path[0] in tq) && (d.qx = d.qy = null);
+                    switch (path[0]) {
+                        case "M":
+                            d.X = path[1];
+                            d.Y = path[2];
+                            break;
+                        case "A":
+                            path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
+                            break;
+                        case "S":
+                            if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
+                                nx = d.x * 2 - d.bx;          // And reflect the previous
+                                ny = d.y * 2 - d.by;          // command's control point relative to the current point.
+                            }
+                            else {                            // or some else or nothing
+                                nx = d.x;
+                                ny = d.y;
+                            }
+                            path = ["C", nx, ny][concat](path.slice(1));
+                            break;
+                        case "T":
+                            if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
+                                d.qx = d.x * 2 - d.qx;        // And make a reflection similar
+                                d.qy = d.y * 2 - d.qy;        // to case "S".
+                            }
+                            else {                            // or something else or nothing
+                                d.qx = d.x;
+                                d.qy = d.y;
+                            }
+                            path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
+                            break;
+                        case "Q":
+                            d.qx = path[1];
+                            d.qy = path[2];
+                            path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
+                            break;
+                        case "L":
+                            path = ["C"][concat](l2c(d.x, d.y, path[1], path[2]));
+                            break;
+                        case "H":
+                            path = ["C"][concat](l2c(d.x, d.y, path[1], d.y));
+                            break;
+                        case "V":
+                            path = ["C"][concat](l2c(d.x, d.y, d.x, path[1]));
+                            break;
+                        case "Z":
+                            path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y));
+                            break;
+                    }
+                    return path;
+                },
+                fixArc = function (pp, i) {
+                    if (pp[i].length > 7) {
+                        pp[i].shift();
+                        var pi = pp[i];
+                        while (pi.length) {
+                            pcoms1[i]="A"; // if created multiple C:s, their original seg is saved
+                            p2 && (pcoms2[i]="A"); // the same as above
+                            pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6)));
+                        }
+                        pp.splice(i, 1);
+                        ii = mmax(p.length, p2 && p2.length || 0);
+                    }
+                },
+                fixM = function (path1, path2, a1, a2, i) {
+                    if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
+                        path2.splice(i, 0, ["M", a2.x, a2.y]);
+                        a1.bx = 0;
+                        a1.by = 0;
+                        a1.x = path1[i][1];
+                        a1.y = path1[i][2];
+                        ii = mmax(p.length, p2 && p2.length || 0);
+                    }
+                },
+                pcoms1 = [], // path commands of original path p
+                pcoms2 = [], // path commands of original path p2
+                pfirst = "", // temporary holder for original path command
+                pcom = ""; // holder for previous path command of original path
+            for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
+                p[i] && (pfirst = p[i][0]); // save current path command
+
+                if (pfirst != "C") // C is not saved yet, because it may be result of conversion
+                {
+                    pcoms1[i] = pfirst; // Save current path command
+                    i && ( pcom = pcoms1[i-1]); // Get previous path command pcom
+                }
+                p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
+
+                if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
+                // which may produce multiple C:s
+                // so we have to make sure that C is also C in original path
+
+                fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
+
+                if (p2) { // the same procedures is done to p2
+                    p2[i] && (pfirst = p2[i][0]);
+                    if (pfirst != "C")
+                    {
+                        pcoms2[i] = pfirst;
+                        i && (pcom = pcoms2[i-1]);
+                    }
+                    p2[i] = processPath(p2[i], attrs2, pcom);
+
+                    if (pcoms2[i]!="A" && pfirst=="C") pcoms2[i]="C";
+
+                    fixArc(p2, i);
+                }
+                fixM(p, p2, attrs, attrs2, i);
+                fixM(p2, p, attrs2, attrs, i);
+                var seg = p[i],
+                    seg2 = p2 && p2[i],
+                    seglen = seg.length,
+                    seg2len = p2 && seg2.length;
+                attrs.x = seg[seglen - 2];
+                attrs.y = seg[seglen - 1];
+                attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
+                attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
+                attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
+                attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
+                attrs2.x = p2 && seg2[seg2len - 2];
+                attrs2.y = p2 && seg2[seg2len - 1];
+            }
+            if (!p2) {
+                pth.curve = pathClone(p);
+            }
+            return p2 ? [p, p2] : p;
+        }, null, pathClone),
+        parseDots = R._parseDots = cacher(function (gradient) {
+            var dots = [];
+            for (var i = 0, ii = gradient.length; i < ii; i++) {
+                var dot = {},
+                    par = gradient[i].match(/^([^:]*):?([\d\.]*)/);
+                dot.color = R.getRGB(par[1]);
+                if (dot.color.error) {
+                    return null;
+                }
+                dot.opacity = dot.color.opacity;
+                dot.color = dot.color.hex;
+                par[2] && (dot.offset = par[2] + "%");
+                dots.push(dot);
+            }
+            for (i = 1, ii = dots.length - 1; i < ii; i++) {
+                if (!dots[i].offset) {
+                    var start = toFloat(dots[i - 1].offset || 0),
+                        end = 0;
+                    for (var j = i + 1; j < ii; j++) {
+                        if (dots[j].offset) {
+                            end = dots[j].offset;
+                            break;
+                        }
+                    }
+                    if (!end) {
+                        end = 100;
+                        j = ii;
+                    }
+                    end = toFloat(end);
+                    var d = (end - start) / (j - i + 1);
+                    for (; i < j; i++) {
+                        start += d;
+                        dots[i].offset = start + "%";
+                    }
+                }
+            }
+            return dots;
+        }),
+        tear = R._tear = function (el, paper) {
+            el == paper.top && (paper.top = el.prev);
+            el == paper.bottom && (paper.bottom = el.next);
+            el.next && (el.next.prev = el.prev);
+            el.prev && (el.prev.next = el.next);
+        },
+        tofront = R._tofront = function (el, paper) {
+            if (paper.top === el) {
+                return;
+            }
+            tear(el, paper);
+            el.next = null;
+            el.prev = paper.top;
+            paper.top.next = el;
+            paper.top = el;
+        },
+        toback = R._toback = function (el, paper) {
+            if (paper.bottom === el) {
+                return;
+            }
+            tear(el, paper);
+            el.next = paper.bottom;
+            el.prev = null;
+            paper.bottom.prev = el;
+            paper.bottom = el;
+        },
+        insertafter = R._insertafter = function (el, el2, paper) {
+            tear(el, paper);
+            el2 == paper.top && (paper.top = el);
+            el2.next && (el2.next.prev = el);
+            el.next = el2.next;
+            el.prev = el2;
+            el2.next = el;
+        },
+        insertbefore = R._insertbefore = function (el, el2, paper) {
+            tear(el, paper);
+            el2 == paper.bottom && (paper.bottom = el);
+            el2.prev && (el2.prev.next = el);
+            el.prev = el2.prev;
+            el2.prev = el;
+            el.next = el2;
+        },
+    /*\
+     * Raphael.toMatrix
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns matrix of transformations applied to a given path
+     > Parameters
+     - path (string) path string
+     - transform (string|array) transformation string
+     = (object) @Matrix
+     \*/
+        toMatrix = R.toMatrix = function (path, transform) {
+            var bb = pathDimensions(path),
+                el = {
+                    _: {
+                        transform: E
+                    },
+                    getBBox: function () {
+                        return bb;
+                    }
+                };
+            extractTransform(el, transform);
+            return el.matrix;
+        },
+    /*\
+     * Raphael.transformPath
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns path transformed by a given transformation
+     > Parameters
+     - path (string) path string
+     - transform (string|array) transformation string
+     = (string) path
+     \*/
+        transformPath = R.transformPath = function (path, transform) {
+            return mapPath(path, toMatrix(path, transform));
+        },
+        extractTransform = R._extractTransform = function (el, tstr) {
+            if (tstr == null) {
+                return el._.transform;
+            }
+            tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
+            var tdata = R.parseTransformString(tstr),
+                deg = 0,
+                dx = 0,
+                dy = 0,
+                sx = 1,
+                sy = 1,
+                _ = el._,
+                m = new Matrix;
+            _.transform = tdata || [];
+            if (tdata) {
+                for (var i = 0, ii = tdata.length; i < ii; i++) {
+                    var t = tdata[i],
+                        tlen = t.length,
+                        command = Str(t[0]).toLowerCase(),
+                        absolute = t[0] != command,
+                        inver = absolute ? m.invert() : 0,
+                        x1,
+                        y1,
+                        x2,
+                        y2,
+                        bb;
+                    if (command == "t" && tlen == 3) {
+                        if (absolute) {
+                            x1 = inver.x(0, 0);
+                            y1 = inver.y(0, 0);
+                            x2 = inver.x(t[1], t[2]);
+                            y2 = inver.y(t[1], t[2]);
+                            m.translate(x2 - x1, y2 - y1);
+                        } else {
+                            m.translate(t[1], t[2]);
+                        }
+                    } else if (command == "r") {
+                        if (tlen == 2) {
+                            bb = bb || el.getBBox(1);
+                            m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+                            deg += t[1];
+                        } else if (tlen == 4) {
+                            if (absolute) {
+                                x2 = inver.x(t[2], t[3]);
+                                y2 = inver.y(t[2], t[3]);
+                                m.rotate(t[1], x2, y2);
+                            } else {
+                                m.rotate(t[1], t[2], t[3]);
+                            }
+                            deg += t[1];
+                        }
+                    } else if (command == "s") {
+                        if (tlen == 2 || tlen == 3) {
+                            bb = bb || el.getBBox(1);
+                            m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+                            sx *= t[1];
+                            sy *= t[tlen - 1];
+                        } else if (tlen == 5) {
+                            if (absolute) {
+                                x2 = inver.x(t[3], t[4]);
+                                y2 = inver.y(t[3], t[4]);
+                                m.scale(t[1], t[2], x2, y2);
+                            } else {
+                                m.scale(t[1], t[2], t[3], t[4]);
+                            }
+                            sx *= t[1];
+                            sy *= t[2];
+                        }
+                    } else if (command == "m" && tlen == 7) {
+                        m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
+                    }
+                    _.dirtyT = 1;
+                    el.matrix = m;
+                }
+            }
+
+            /*\
+             * Element.matrix
+             [ property (object) ]
+             **
+             * Keeps @Matrix object, which represents element transformation
+             \*/
+            el.matrix = m;
+
+            _.sx = sx;
+            _.sy = sy;
+            _.deg = deg;
+            _.dx = dx = m.e;
+            _.dy = dy = m.f;
+
+            if (sx == 1 && sy == 1 && !deg && _.bbox) {
+                _.bbox.x += +dx;
+                _.bbox.y += +dy;
+            } else {
+                _.dirtyT = 1;
+            }
+        },
+        getEmpty = function (item) {
+            var l = item[0];
+            switch (l.toLowerCase()) {
+                case "t": return [l, 0, 0];
+                case "m": return [l, 1, 0, 0, 1, 0, 0];
+                case "r": if (item.length == 4) {
+                    return [l, 0, item[2], item[3]];
+                } else {
+                    return [l, 0];
+                }
+                case "s": if (item.length == 5) {
+                    return [l, 1, 1, item[3], item[4]];
+                } else if (item.length == 3) {
+                    return [l, 1, 1];
+                } else {
+                    return [l, 1];
+                }
+            }
+        },
+        equaliseTransform = R._equaliseTransform = function (t1, t2) {
+            t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
+            t1 = R.parseTransformString(t1) || [];
+            t2 = R.parseTransformString(t2) || [];
+            var maxlength = mmax(t1.length, t2.length),
+                from = [],
+                to = [],
+                i = 0, j, jj,
+                tt1, tt2;
+            for (; i < maxlength; i++) {
+                tt1 = t1[i] || getEmpty(t2[i]);
+                tt2 = t2[i] || getEmpty(tt1);
+                if ((tt1[0] != tt2[0]) ||
+                    (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
+                    (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
+                ) {
+                    return;
+                }
+                from[i] = [];
+                to[i] = [];
+                for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) {
+                    j in tt1 && (from[i][j] = tt1[j]);
+                    j in tt2 && (to[i][j] = tt2[j]);
+                }
+            }
+            return {
+                from: from,
+                to: to
+            };
+        };
+    R._getContainer = function (x, y, w, h) {
+        var container;
+        container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x;
+        if (container == null) {
+            return;
+        }
+        if (container.tagName) {
+            if (y == null) {
+                return {
+                    container: container,
+                    width: container.style.pixelWidth || container.offsetWidth,
+                    height: container.style.pixelHeight || container.offsetHeight
+                };
+            } else {
+                return {
+                    container: container,
+                    width: y,
+                    height: w
+                };
+            }
+        }
+        return {
+            container: 1,
+            x: x,
+            y: y,
+            width: w,
+            height: h
+        };
+    };
+    /*\
+     * Raphael.pathToRelative
+     [ method ]
+     **
+     * Utility method
+     **
+     * Converts path to relative form
+     > Parameters
+     - pathString (string|array) path string or array of segments
+     = (array) array of segments.
+     \*/
+    R.pathToRelative = pathToRelative;
+    R._engine = {};
+    /*\
+     * Raphael.path2curve
+     [ method ]
+     **
+     * Utility method
+     **
+     * Converts path to a new path where all segments are cubic bezier curves.
+     > Parameters
+     - pathString (string|array) path string or array of segments
+     = (array) array of segments.
+     \*/
+    R.path2curve = path2curve;
+    /*\
+     * Raphael.matrix
+     [ method ]
+     **
+     * Utility method
+     **
+     * Returns matrix based on given parameters.
+     > Parameters
+     - a (number)
+     - b (number)
+     - c (number)
+     - d (number)
+     - e (number)
+     - f (number)
+     = (object) @Matrix
+     \*/
+    R.matrix = function (a, b, c, d, e, f) {
+        return new Matrix(a, b, c, d, e, f);
+    };
+    function Matrix(a, b, c, d, e, f) {
+        if (a != null) {
+            this.a = +a;
+            this.b = +b;
+            this.c = +c;
+            this.d = +d;
+            this.e = +e;
+            this.f = +f;
+        } else {
+            this.a = 1;
+            this.b = 0;
+            this.c = 0;
+            this.d = 1;
+            this.e = 0;
+            this.f = 0;
+        }
+    }
+    (function (matrixproto) {
+        /*\
+         * Matrix.add
+         [ method ]
+         **
+         * Adds given matrix to existing one.
+         > Parameters
+         - a (number)
+         - b (number)
+         - c (number)
+         - d (number)
+         - e (number)
+         - f (number)
+         or
+         - matrix (object) @Matrix
+         \*/
+        matrixproto.add = function (a, b, c, d, e, f) {
+            var out = [[], [], []],
+                m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
+                matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
+                x, y, z, res;
+
+            if (a && a instanceof Matrix) {
+                matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
+            }
+
+            for (x = 0; x < 3; x++) {
+                for (y = 0; y < 3; y++) {
+                    res = 0;
+                    for (z = 0; z < 3; z++) {
+                        res += m[x][z] * matrix[z][y];
+                    }
+                    out[x][y] = res;
+                }
+            }
+            this.a = out[0][0];
+            this.b = out[1][0];
+            this.c = out[0][1];
+            this.d = out[1][1];
+            this.e = out[0][2];
+            this.f = out[1][2];
+        };
+        /*\
+         * Matrix.invert
+         [ method ]
+         **
+         * Returns inverted version of the matrix
+         = (object) @Matrix
+         \*/
+        matrixproto.invert = function () {
+            var me = this,
+                x = me.a * me.d - me.b * me.c;
+            return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
+        };
+        /*\
+         * Matrix.clone
+         [ method ]
+         **
+         * Returns copy of the matrix
+         = (object) @Matrix
+         \*/
+        matrixproto.clone = function () {
+            return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
+        };
+        /*\
+         * Matrix.translate
+         [ method ]
+         **
+         * Translate the matrix
+         > Parameters
+         - x (number)
+         - y (number)
+         \*/
+        matrixproto.translate = function (x, y) {
+            this.add(1, 0, 0, 1, x, y);
+        };
+        /*\
+         * Matrix.scale
+         [ method ]
+         **
+         * Scales the matrix
+         > Parameters
+         - x (number)
+         - y (number) #optional
+         - cx (number) #optional
+         - cy (number) #optional
+         \*/
+        matrixproto.scale = function (x, y, cx, cy) {
+            y == null && (y = x);
+            (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
+            this.add(x, 0, 0, y, 0, 0);
+            (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
+        };
+        /*\
+         * Matrix.rotate
+         [ method ]
+         **
+         * Rotates the matrix
+         > Parameters
+         - a (number)
+         - x (number)
+         - y (number)
+         \*/
+        matrixproto.rotate = function (a, x, y) {
+            a = R.rad(a);
+            x = x || 0;
+            y = y || 0;
+            var cos = +math.cos(a).toFixed(9),
+                sin = +math.sin(a).toFixed(9);
+            this.add(cos, sin, -sin, cos, x, y);
+            this.add(1, 0, 0, 1, -x, -y);
+        };
+        /*\
+         * Matrix.x
+         [ method ]
+         **
+         * Return x coordinate for given point after transformation described by the matrix. See also @Matrix.y
+         > Parameters
+         - x (number)
+         - y (number)
+         = (number) x
+         \*/
+        matrixproto.x = function (x, y) {
+            return x * this.a + y * this.c + this.e;
+        };
+        /*\
+         * Matrix.y
+         [ method ]
+         **
+         * Return y coordinate for given point after transformation described by the matrix. See also @Matrix.x
+         > Parameters
+         - x (number)
+         - y (number)
+         = (number) y
+         \*/
+        matrixproto.y = function (x, y) {
+            return x * this.b + y * this.d + this.f;
+        };
+        matrixproto.get = function (i) {
+            return +this[Str.fromCharCode(97 + i)].toFixed(4);
+        };
+        matrixproto.toString = function () {
+            return R.svg ?
+            "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
+                [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
+        };
+        matrixproto.toFilter = function () {
+            return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
+                ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
+                ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
+        };
+        matrixproto.offset = function () {
+            return [this.e.toFixed(4), this.f.toFixed(4)];
+        };
+        function norm(a) {
+            return a[0] * a[0] + a[1] * a[1];
+        }
+        function normalize(a) {
+            var mag = math.sqrt(norm(a));
+            a[0] && (a[0] /= mag);
+            a[1] && (a[1] /= mag);
+        }
+        /*\
+         * Matrix.split
+         [ method ]
+         **
+         * Splits matrix into primitive transformations
+         = (object) in format:
+         o dx (number) translation by x
+         o dy (number) translation by y
+         o scalex (number) scale by x
+         o scaley (number) scale by y
+         o shear (number) shear
+         o rotate (number) rotation in deg
+         o isSimple (boolean) could it be represented via simple transformations
+         \*/
+        matrixproto.split = function () {
+            var out = {};
+            // translation
+            out.dx = this.e;
+            out.dy = this.f;
+
+            // scale and shear
+            var row = [[this.a, this.c], [this.b, this.d]];
+            out.scalex = math.sqrt(norm(row[0]));
+            normalize(row[0]);
+
+            out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
+            row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
+
+            out.scaley = math.sqrt(norm(row[1]));
+            normalize(row[1]);
+            out.shear /= out.scaley;
+
+            // rotation
+            var sin = -row[0][1],
+                cos = row[1][1];
+            if (cos < 0) {
+                out.rotate = R.deg(math.acos(cos));
+                if (sin < 0) {
+                    out.rotate = 360 - out.rotate;
+                }
+            } else {
+                out.rotate = R.deg(math.asin(sin));
+            }
+
+            out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
+            out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
+            out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
+            return out;
+        };
+        /*\
+         * Matrix.toTransformString
+         [ method ]
+         **
+         * Return transform string that represents given matrix
+         = (string) transform string
+         \*/
+        matrixproto.toTransformString = function (shorter) {
+            var s = shorter || this[split]();
+            if (s.isSimple) {
+                s.scalex = +s.scalex.toFixed(4);
+                s.scaley = +s.scaley.toFixed(4);
+                s.rotate = +s.rotate.toFixed(4);
+                return  (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) +
+                    (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
+                    (s.rotate ? "r" + [s.rotate, 0, 0] : E);
+            } else {
+                return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
+            }
+        };
+    })(Matrix.prototype);
+
+    var preventDefault = function () {
+            this.returnValue = false;
+        },
+        preventTouch = function () {
+            return this.originalEvent.preventDefault();
+        },
+        stopPropagation = function () {
+            this.cancelBubble = true;
+        },
+        stopTouch = function () {
+            return this.originalEvent.stopPropagation();
+        },
+        getEventPosition = function (e) {
+            var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+                scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+
+            return {
+                x: e.clientX + scrollX,
+                y: e.clientY + scrollY
+            };
+        },
+        addEvent = (function () {
+            if (g.doc.addEventListener) {
+                return function (obj, type, fn, element) {
+                    var f = function (e) {
+                        var pos = getEventPosition(e);
+                        return fn.call(element, e, pos.x, pos.y);
+                    };
+                    obj.addEventListener(type, f, false);
+
+                    if (supportsTouch && touchMap[type]) {
+                        var _f = function (e) {
+                            var pos = getEventPosition(e),
+                                olde = e;
+
+                            for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
+                                if (e.targetTouches[i].target == obj) {
+                                    e = e.targetTouches[i];
+                                    e.originalEvent = olde;
+                                    e.preventDefault = preventTouch;
+                                    e.stopPropagation = stopTouch;
+                                    break;
+                                }
+                            }
+
+                            return fn.call(element, e, pos.x, pos.y);
+                        };
+                        obj.addEventListener(touchMap[type], _f, false);
+                    }
+
+                    return function () {
+                        obj.removeEventListener(type, f, false);
+
+                        if (supportsTouch && touchMap[type])
+                            obj.removeEventListener(touchMap[type], _f, false);
+
+                        return true;
+                    };
+                };
+            } else if (g.doc.attachEvent) {
+                return function (obj, type, fn, element) {
+                    var f = function (e) {
+                        e = e || g.win.event;
+                        var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+                            scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+                            x = e.clientX + scrollX,
+                            y = e.clientY + scrollY;
+                        e.preventDefault = e.preventDefault || preventDefault;
+                        e.stopPropagation = e.stopPropagation || stopPropagation;
+                        return fn.call(element, e, x, y);
+                    };
+                    obj.attachEvent("on" + type, f);
+                    var detacher = function () {
+                        obj.detachEvent("on" + type, f);
+                        return true;
+                    };
+                    return detacher;
+                };
+            }
+        })(),
+        drag = [],
+        dragMove = function (e) {
+            var x = e.clientX,
+                y = e.clientY,
+                scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+                scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
+                dragi,
+                j = drag.length;
+            while (j--) {
+                dragi = drag[j];
+                if (supportsTouch && e.touches) {
+                    var i = e.touches.length,
+                        touch;
+                    while (i--) {
+                        touch = e.touches[i];
+                        if (touch.identifier == dragi.el._drag.id) {
+                            x = touch.clientX;
+                            y = touch.clientY;
+                            (e.originalEvent ? e.originalEvent : e).preventDefault();
+                            break;
+                        }
+                    }
+                } else {
+                    e.preventDefault();
+                }
+                var node = dragi.el.node,
+                    o,
+                    next = node.nextSibling,
+                    parent = node.parentNode,
+                    display = node.style.display;
+                g.win.opera && parent.removeChild(node);
+                node.style.display = "none";
+                o = dragi.el.paper.getElementByPoint(x, y);
+                node.style.display = display;
+                g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+                o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o);
+                x += scrollX;
+                y += scrollY;
+                eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+            }
+        },
+        dragUp = function (e) {
+            R.unmousemove(dragMove).unmouseup(dragUp);
+            var i = drag.length,
+                dragi;
+            while (i--) {
+                dragi = drag[i];
+                dragi.el._drag = {};
+                eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+            }
+            drag = [];
+        },
+    /*\
+     * Raphael.el
+     [ property (object) ]
+     **
+     * You can add your own method to elements. This is usefull when you want to hack default functionality or
+     * want to wrap some common transformation or attributes in one method. In difference to canvas methods,
+     * you can redefine element method at any time. Expending element methods wouldn’t affect set.
+     > Usage
+     | Raphael.el.red = function () {
+     |     this.attr({fill: "#f00"});
+     | };
+     | // then use it
+     | paper.circle(100, 100, 20).red();
+     \*/
+        elproto = R.el = {};
+    /*\
+     * Element.click
+     [ method ]
+     **
+     * Adds event handler for click for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unclick
+     [ method ]
+     **
+     * Removes event handler for click for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.dblclick
+     [ method ]
+     **
+     * Adds event handler for double click for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.undblclick
+     [ method ]
+     **
+     * Removes event handler for double click for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.mousedown
+     [ method ]
+     **
+     * Adds event handler for mousedown for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unmousedown
+     [ method ]
+     **
+     * Removes event handler for mousedown for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.mousemove
+     [ method ]
+     **
+     * Adds event handler for mousemove for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unmousemove
+     [ method ]
+     **
+     * Removes event handler for mousemove for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.mouseout
+     [ method ]
+     **
+     * Adds event handler for mouseout for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unmouseout
+     [ method ]
+     **
+     * Removes event handler for mouseout for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.mouseover
+     [ method ]
+     **
+     * Adds event handler for mouseover for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unmouseover
+     [ method ]
+     **
+     * Removes event handler for mouseover for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.mouseup
+     [ method ]
+     **
+     * Adds event handler for mouseup for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.unmouseup
+     [ method ]
+     **
+     * Removes event handler for mouseup for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.touchstart
+     [ method ]
+     **
+     * Adds event handler for touchstart for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.untouchstart
+     [ method ]
+     **
+     * Removes event handler for touchstart for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.touchmove
+     [ method ]
+     **
+     * Adds event handler for touchmove for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.untouchmove
+     [ method ]
+     **
+     * Removes event handler for touchmove for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.touchend
+     [ method ]
+     **
+     * Adds event handler for touchend for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.untouchend
+     [ method ]
+     **
+     * Removes event handler for touchend for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+
+    /*\
+     * Element.touchcancel
+     [ method ]
+     **
+     * Adds event handler for touchcancel for the element.
+     > Parameters
+     - handler (function) handler for the event
+     = (object) @Element
+     \*/
+    /*\
+     * Element.untouchcancel
+     [ method ]
+     **
+     * Removes event handler for touchcancel for the element.
+     > Parameters
+     - handler (function) #optional handler for the event
+     = (object) @Element
+     \*/
+    for (var i = events.length; i--;) {
+        (function (eventName) {
+            R[eventName] = elproto[eventName] = function (fn, scope) {
+                if (R.is(fn, "function")) {
+                    this.events = this.events || [];
+                    this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)});
+                }
+                return this;
+            };
+            R["un" + eventName] = elproto["un" + eventName] = function (fn) {
+                var events = this.events || [],
+                    l = events.length;
+                while (l--){
+                    if (events[l].name == eventName && (R.is(fn, "undefined") || events[l].f == fn)) {
+                        events[l].unbind();
+                        events.splice(l, 1);
+                        !events.length && delete this.events;
+                    }
+                }
+                return this;
+            };
+        })(events[i]);
+    }
+
+    /*\
+     * Element.data
+     [ method ]
+     **
+     * Adds or retrieves given value asociated with given key.
+     **
+     * See also @Element.removeData
+     > Parameters
+     - key (string) key to store data
+     - value (any) #optional value to store
+     = (object) @Element
+     * or, if value is not specified:
+     = (any) value
+     * or, if key and value are not specified:
+     = (object) Key/value pairs for all the data associated with the element.
+     > Usage
+     | for (var i = 0, i < 5, i++) {
+     |     paper.circle(10 + 15 * i, 10, 10)
+     |          .attr({fill: "#000"})
+     |          .data("i", i)
+     |          .click(function () {
+     |             alert(this.data("i"));
+     |          });
+     | }
+     \*/
+    elproto.data = function (key, value) {
+        var data = eldata[this.id] = eldata[this.id] || {};
+        if (arguments.length == 0) {
+            return data;
+        }
+        if (arguments.length == 1) {
+            if (R.is(key, "object")) {
+                for (var i in key) if (key[has](i)) {
+                    this.data(i, key[i]);
+                }
+                return this;
+            }
+            eve("raphael.data.get." + this.id, this, data[key], key);
+            return data[key];
+        }
+        data[key] = value;
+        eve("raphael.data.set." + this.id, this, value, key);
+        return this;
+    };
+
+    elproto.datum = function(){
+        return arguments.length == 0 ? this._bindData : ((this._bindData = arguments[0]), this);
+    };
+
+    /*\
+     * Element.removeData
+     [ method ]
+     **
+     * Removes value associated with an element by given key.
+     * If key is not provided, removes all the data of the element.
+     > Parameters
+     - key (string) #optional key
+     = (object) @Element
+     \*/
+    elproto.removeData = function (key) {
+        if (key == null) {
+            eldata[this.id] = {};
+        } else {
+            eldata[this.id] && delete eldata[this.id][key];
+        }
+        return this;
+    };
+    /*\
+     * Element.getData
+     [ method ]
+     **
+     * Retrieves the element data
+     = (object) data
+     \*/
+    elproto.getData = function () {
+        return clone(eldata[this.id] || {});
+    };
+    /*\
+     * Element.hover
+     [ method ]
+     **
+     * Adds event handlers for hover for the element.
+     > Parameters
+     - f_in (function) handler for hover in
+     - f_out (function) handler for hover out
+     - icontext (object) #optional context for hover in handler
+     - ocontext (object) #optional context for hover out handler
+     = (object) @Element
+     \*/
+    elproto.hover = function (f_in, f_out, scope_in, scope_out) {
+        return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
+    };
+    /*\
+     * Element.unhover
+     [ method ]
+     **
+     * Removes event handlers for hover for the element.
+     > Parameters
+     - f_in (function) handler for hover in
+     - f_out (function) handler for hover out
+     = (object) @Element
+     \*/
+    elproto.unhover = function (f_in, f_out) {
+        return this.unmouseover(f_in).unmouseout(f_out);
+    };
+    var draggable = [];
+    /*\
+     * Element.drag
+     [ method ]
+     **
+     * Adds event handlers for drag of the element.
+     > Parameters
+     - onmove (function) handler for moving
+     - onstart (function) handler for drag start
+     - onend (function) handler for drag end
+     - mcontext (object) #optional context for moving handler
+     - scontext (object) #optional context for drag start handler
+     - econtext (object) #optional context for drag end handler
+     * Additionaly following `drag` events will be triggered: `drag.start.<id>` on start,
+     * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element will be dragged over another element
+     * `drag.over.<id>` will be fired as well.
+     *
+     * Start event and start handler will be called in specified context or in context of the element with following parameters:
+     o x (number) x position of the mouse
+     o y (number) y position of the mouse
+     o event (object) DOM event object
+     * Move event and move handler will be called in specified context or in context of the element with following parameters:
+     o dx (number) shift by x from the start point
+     o dy (number) shift by y from the start point
+     o x (number) x position of the mouse
+     o y (number) y position of the mouse
+     o event (object) DOM event object
+     * End event and end handler will be called in specified context or in context of the element with following parameters:
+     o event (object) DOM event object
+     = (object) @Element
+     \*/
+    elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
+        function start(e) {
+            (e.originalEvent || e).preventDefault();
+            var x = e.clientX,
+                y = e.clientY,
+                scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
+                scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
+            this._drag.id = e.identifier;
+            if (supportsTouch && e.touches) {
+                var i = e.touches.length, touch;
+                while (i--) {
+                    touch = e.touches[i];
+                    this._drag.id = touch.identifier;
+                    if (touch.identifier == this._drag.id) {
+                        x = touch.clientX;
+                        y = touch.clientY;
+                        break;
+                    }
+                }
+            }
+            this._drag.x = x + scrollX;
+            this._drag.y = y + scrollY;
+            !drag.length && R.mousemove(dragMove).mouseup(dragUp);
+            drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
+            onstart && eve.on("raphael.drag.start." + this.id, onstart);
+            onmove && eve.on("raphael.drag.move." + this.id, onmove);
+            onend && eve.on("raphael.drag.end." + this.id, onend);
+            eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
+        }
+        this._drag = {};
+        draggable.push({el: this, start: start});
+        this.mousedown(start);
+        return this;
+    };
+    /*\
+     * Element.onDragOver
+     [ method ]
+     **
+     * Shortcut for assigning event handler for `drag.over.<id>` event, where id is id of the element (see @Element.id).
+     > Parameters
+     - f (function) handler for event, first argument would be the element you are dragging over
+     \*/
+    elproto.onDragOver = function (f) {
+        f ? eve.on("raphael.drag.over." + this.id, f) : eve.unbind("raphael.drag.over." + this.id);
+    };
+    /*\
+     * Element.undrag
+     [ method ]
+     **
+     * Removes all drag event handlers from given element.
+     \*/
+    elproto.undrag = function () {
+        var i = draggable.length;
+        while (i--) if (draggable[i].el == this) {
+            this.unmousedown(draggable[i].start);
+            draggable.splice(i, 1);
+            eve.unbind("raphael.drag.*." + this.id);
+        }
+        !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
+        drag = [];
+    };
+    /*\
+     * Paper.circle
+     [ method ]
+     **
+     * Draws a circle.
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the centre
+     - y (number) y coordinate of the centre
+     - r (number) radius
+     = (object) Raphaël element object with type “circle”
+     **
+     > Usage
+     | var c = paper.circle(50, 50, 40);
+     \*/
+    paperproto.circle = function (x, y, r) {
+        var out = R._engine.circle(this, x || 0, y || 0, r || 0);
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.rect
+     [ method ]
+     *
+     * Draws a rectangle.
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the top left corner
+     - y (number) y coordinate of the top left corner
+     - width (number) width
+     - height (number) height
+     - r (number) #optional radius for rounded corners, default is 0
+     = (object) Raphaël element object with type “rect”
+     **
+     > Usage
+     | // regular rectangle
+     | var c = paper.rect(10, 10, 50, 50);
+     | // rectangle with rounded corners
+     | var c = paper.rect(40, 40, 50, 50, 10);
+     \*/
+    paperproto.rect = function (x, y, w, h, r) {
+        var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0);
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.ellipse
+     [ method ]
+     **
+     * Draws an ellipse.
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the centre
+     - y (number) y coordinate of the centre
+     - rx (number) horizontal radius
+     - ry (number) vertical radius
+     = (object) Raphaël element object with type “ellipse”
+     **
+     > Usage
+     | var c = paper.ellipse(50, 50, 40, 20);
+     \*/
+    paperproto.ellipse = function (x, y, rx, ry) {
+        var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0);
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.path
+     [ method ]
+     **
+     * Creates a path element by given path data string.
+     > Parameters
+     - pathString (string) #optional path string in SVG format.
+     * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example:
+     | "M10,20L30,40"
+     * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative.
+     *
+     # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a>.</p>
+     # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
+     # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
+     # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
+     # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
+     # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
+     # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
+     # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
+     # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
+     # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
+     # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
+     # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
+     # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
+     * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier.
+     * Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning.
+     > Usage
+     | var c = paper.path("M10 10L90 90");
+     | // draw a diagonal line:
+     | // move to 10,10, line to 90,90
+     * For example of path strings, check out these icons: http://raphaeljs.com/icons/
+     \*/
+    paperproto.path = function (pathString) {
+        pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E);
+        var out = R._engine.path(R.format[apply](R, arguments), this);
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.image
+     [ method ]
+     **
+     * Embeds an image into the surface.
+     **
+     > Parameters
+     **
+     - src (string) URI of the source image
+     - x (number) x coordinate position
+     - y (number) y coordinate position
+     - width (number) width of the image
+     - height (number) height of the image
+     = (object) Raphaël element object with type “image”
+     **
+     > Usage
+     | var c = paper.image("apple.png", 10, 10, 80, 80);
+     \*/
+    paperproto.image = function (src, x, y, w, h) {
+        var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0);
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.text
+     [ method ]
+     **
+     * Draws a text string. If you need line breaks, put “\n” in the string.
+     **
+     > Parameters
+     **
+     - x (number) x coordinate position
+     - y (number) y coordinate position
+     - text (string) The text string to draw
+     = (object) Raphaël element object with type “text”
+     **
+     > Usage
+     | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
+     \*/
+    paperproto.text = function (x, y, text) {
+        var out = R._engine.text(this, x || 0, y || 0, Str(text));
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Paper.set
+     [ method ]
+     **
+     * Creates array-like object to keep and operate several elements at once.
+     * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements.
+     * Sets act as pseudo elements — all methods available to an element can be used on a set.
+     = (object) array-like object that represents set of elements
+     **
+     > Usage
+     | var st = paper.set();
+     | st.push(
+     |     paper.circle(10, 10, 5),
+     |     paper.circle(30, 10, 5)
+     | );
+     | st.attr({fill: "red"}); // changes the fill of both circles
+     \*/
+    paperproto.set = function (itemsArray) {
+        !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length));
+        var out = new Set(itemsArray);
+        this.__set__ && this.__set__.push(out);
+        out["paper"] = this;
+        out["type"] = "set";
+        return out;
+    };
+    /*\
+     * Paper.setStart
+     [ method ]
+     **
+     * Creates @Paper.set. All elements that will be created after calling this method and before calling
+     * @Paper.setFinish will be added to the set.
+     **
+     > Usage
+     | paper.setStart();
+     | paper.circle(10, 10, 5),
+     | paper.circle(30, 10, 5)
+     | var st = paper.setFinish();
+     | st.attr({fill: "red"}); // changes the fill of both circles
+     \*/
+    paperproto.setStart = function (set) {
+        this.__set__ = set || this.set();
+    };
+    /*\
+     * Paper.setFinish
+     [ method ]
+     **
+     * See @Paper.setStart. This method finishes catching and returns resulting set.
+     **
+     = (object) set
+     \*/
+    paperproto.setFinish = function (set) {
+        var out = this.__set__;
+        delete this.__set__;
+        return out;
+    };
+    /*\
+     * Paper.getSize
+     [ method ]
+     **
+     * Obtains current paper actual size.
+     **
+     = (object)
+     \*/
+    paperproto.getSize = function () {
+        var container = this.canvas.parentNode;
+        return {
+            width: container.offsetWidth,
+            height: container.offsetHeight
+        };
+    };
+    /*\
+     * Paper.setSize
+     [ method ]
+     **
+     * If you need to change dimensions of the canvas call this method
+     **
+     > Parameters
+     **
+     - width (number) new width of the canvas
+     - height (number) new height of the canvas
+     \*/
+    paperproto.setSize = function (width, height) {
+        return R._engine.setSize.call(this, width, height);
+    };
+    /*\
+     * Paper.setViewBox
+     [ method ]
+     **
+     * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by
+     * specifying new boundaries.
+     **
+     > Parameters
+     **
+     - x (number) new x position, default is `0`
+     - y (number) new y position, default is `0`
+     - w (number) new width of the canvas
+     - h (number) new height of the canvas
+     - fit (boolean) `true` if you want graphics to fit into new boundary box
+     \*/
+    paperproto.setViewBox = function (x, y, w, h, fit) {
+        return R._engine.setViewBox.call(this, x, y, w, h, fit);
+    };
+    /*\
+     * Paper.top
+     [ property ]
+     **
+     * Points to the topmost element on the paper
+     \*/
+    /*\
+     * Paper.bottom
+     [ property ]
+     **
+     * Points to the bottom element on the paper
+     \*/
+    paperproto.top = paperproto.bottom = null;
+    /*\
+     * Paper.raphael
+     [ property ]
+     **
+     * Points to the @Raphael object/function
+     \*/
+    paperproto.raphael = R;
+    var getOffset = function (elem) {
+        var box = elem.getBoundingClientRect(),
+            doc = elem.ownerDocument,
+            body = doc.body,
+            docElem = doc.documentElement,
+            clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+            top  = box.top  + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
+            left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
+        return {
+            y: top,
+            x: left
+        };
+    };
+    /*\
+     * Paper.getElementByPoint
+     [ method ]
+     **
+     * Returns you topmost element under given point.
+     **
+     = (object) Raphaël element object
+     > Parameters
+     **
+     - x (number) x coordinate from the top left corner of the window
+     - y (number) y coordinate from the top left corner of the window
+     > Usage
+     | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+     \*/
+    paperproto.getElementByPoint = function (x, y) {
+        var paper = this,
+            svg = paper.canvas,
+            target = g.doc.elementFromPoint(x, y);
+        if (g.win.opera && target.tagName == "svg") {
+            var so = getOffset(svg),
+                sr = svg.createSVGRect();
+            sr.x = x - so.x;
+            sr.y = y - so.y;
+            sr.width = sr.height = 1;
+            var hits = svg.getIntersectionList(sr, null);
+            if (hits.length) {
+                target = hits[hits.length - 1];
+            }
+        }
+        if (!target) {
+            return null;
+        }
+        while (target.parentNode && target != svg.parentNode && !target.raphael) {
+            target = target.parentNode;
+        }
+        target == paper.canvas.parentNode && (target = svg);
+        target = target && target.raphael ? paper.getById(target.raphaelid) : null;
+        return target;
+    };
+
+    /*\
+     * Paper.getElementsByBBox
+     [ method ]
+     **
+     * Returns set of elements that have an intersecting bounding box
+     **
+     > Parameters
+     **
+     - bbox (object) bbox to check with
+     = (object) @Set
+     \*/
+    paperproto.getElementsByBBox = function (bbox) {
+        var set = this.set();
+        this.forEach(function (el) {
+            if (R.isBBoxIntersect(el.getBBox(), bbox)) {
+                set.push(el);
+            }
+        });
+        return set;
+    };
+
+    /*\
+     * Paper.getById
+     [ method ]
+     **
+     * Returns you element by its internal ID.
+     **
+     > Parameters
+     **
+     - id (number) id
+     = (object) Raphaël element object
+     \*/
+    paperproto.getById = function (id) {
+        var bot = this.bottom;
+        while (bot) {
+            if (bot.id == id) {
+                return bot;
+            }
+            bot = bot.next;
+        }
+        return null;
+    };
+    /*\
+     * Paper.forEach
+     [ method ]
+     **
+     * Executes given function for each element on the paper
+     *
+     * If callback function returns `false` it will stop loop running.
+     **
+     > Parameters
+     **
+     - callback (function) function to run
+     - thisArg (object) context object for the callback
+     = (object) Paper object
+     > Usage
+     | paper.forEach(function (el) {
+     |     el.attr({ stroke: "blue" });
+     | });
+     \*/
+    paperproto.forEach = function (callback, thisArg) {
+        var bot = this.bottom;
+        while (bot) {
+            if (callback.call(thisArg, bot) === false) {
+                return this;
+            }
+            bot = bot.next;
+        }
+        return this;
+    };
+    /*\
+     * Paper.getElementsByPoint
+     [ method ]
+     **
+     * Returns set of elements that have common point inside
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the point
+     - y (number) y coordinate of the point
+     = (object) @Set
+     \*/
+    paperproto.getElementsByPoint = function (x, y) {
+        var set = this.set();
+        this.forEach(function (el) {
+            if (el.isPointInside(x, y)) {
+                set.push(el);
+            }
+        });
+        return set;
+    };
+    function x_y() {
+        return this.x + S + this.y;
+    }
+    function x_y_w_h() {
+        return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
+    }
+    /*\
+     * Element.isPointInside
+     [ method ]
+     **
+     * Determine if given point is inside this element’s shape
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the point
+     - y (number) y coordinate of the point
+     = (boolean) `true` if point inside the shape
+     \*/
+    elproto.isPointInside = function (x, y) {
+        var rp = this.realPath = getPath[this.type](this);
+        if (this.attr('transform') && this.attr('transform').length) {
+            rp = R.transformPath(rp, this.attr('transform'));
+        }
+        return R.isPointInsidePath(rp, x, y);
+    };
+    /*\
+     * Element.getBBox
+     [ method ]
+     **
+     * Return bounding box for a given element
+     **
+     > Parameters
+     **
+     - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`.
+     = (object) Bounding box object:
+     o {
+     o     x: (number) top left corner x
+     o     y: (number) top left corner y
+     o     x2: (number) bottom right corner x
+     o     y2: (number) bottom right corner y
+     o     width: (number) width
+     o     height: (number) height
+     o }
+     \*/
+    elproto.getBBox = function (isWithoutTransform) {
+        if (this.removed) {
+            return {};
+        }
+        var _ = this._;
+        if (isWithoutTransform) {
+            if (_.dirty || !_.bboxwt) {
+                this.realPath = getPath[this.type](this);
+                _.bboxwt = pathDimensions(this.realPath);
+                _.bboxwt.toString = x_y_w_h;
+                _.dirty = 0;
+            }
+            return _.bboxwt;
+        }
+        if (_.dirty || _.dirtyT || !_.bbox) {
+            if (_.dirty || !this.realPath) {
+                _.bboxwt = 0;
+                this.realPath = getPath[this.type](this);
+            }
+            _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
+            _.bbox.toString = x_y_w_h;
+            _.dirty = _.dirtyT = 0;
+        }
+        return _.bbox;
+    };
+    /*\
+     * Element.clone
+     [ method ]
+     **
+     = (object) clone of a given element
+     **
+     \*/
+    elproto.clone = function () {
+        if (this.removed) {
+            return null;
+        }
+        var out = this.paper[this.type]().attr(this.attr());
+        this.__set__ && this.__set__.push(out);
+        return out;
+    };
+    /*\
+     * Element.glow
+     [ method ]
+     **
+     * Return set of elements that create glow-like effect around given element. See @Paper.set.
+     *
+     * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself.
+     **
+     > Parameters
+     **
+     - glow (object) #optional parameters object with all properties optional:
+     o {
+     o     width (number) size of the glow, default is `10`
+     o     fill (boolean) will it be filled, default is `false`
+     o     opacity (number) opacity, default is `0.5`
+     o     offsetx (number) horizontal offset, default is `0`
+     o     offsety (number) vertical offset, default is `0`
+     o     color (string) glow colour, default is `black`
+     o }
+     = (object) @Paper.set of elements that represents glow
+     \*/
+    elproto.glow = function (glow) {
+        if (this.type == "text") {
+            return null;
+        }
+        glow = glow || {};
+        var s = {
+                width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
+                fill: glow.fill || false,
+                opacity: glow.opacity == null ? .5 : glow.opacity,
+                offsetx: glow.offsetx || 0,
+                offsety: glow.offsety || 0,
+                color: glow.color || "#000"
+            },
+            c = s.width / 2,
+            r = this.paper,
+            out = r.set(),
+            path = this.realPath || getPath[this.type](this);
+        path = this.matrix ? mapPath(path, this.matrix) : path;
+        for (var i = 1; i < c + 1; i++) {
+            out.push(r.path(path).attr({
+                stroke: s.color,
+                fill: s.fill ? s.color : "none",
+                "stroke-linejoin": "round",
+                "stroke-linecap": "round",
+                "stroke-width": +(s.width / c * i).toFixed(3),
+                opacity: +(s.opacity / c).toFixed(3)
+            }));
+        }
+        return out.insertBefore(this).translate(s.offsetx, s.offsety);
+    };
+    var curveslengths = {},
+        getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
+            if (length == null) {
+                return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
+            } else {
+                return R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
+            }
+        },
+        getLengthFactory = function (istotal, subpath) {
+            return function (path, length, onlystart) {
+                path = path2curve(path);
+                var x, y, p, l, sp = "", subpaths = {}, point,
+                    len = 0;
+                for (var i = 0, ii = path.length; i < ii; i++) {
+                    p = path[i];
+                    if (p[0] == "M") {
+                        x = +p[1];
+                        y = +p[2];
+                    } else {
+                        l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+                        if (len + l > length) {
+                            if (subpath && !subpaths.start) {
+                                point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+                                sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
+                                if (onlystart) {return sp;}
+                                subpaths.start = sp;
+                                sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
+                                len += l;
+                                x = +p[5];
+                                y = +p[6];
+                                continue;
+                            }
+                            if (!istotal && !subpath) {
+                                point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+                                return {x: point.x, y: point.y, alpha: point.alpha};
+                            }
+                        }
+                        len += l;
+                        x = +p[5];
+                        y = +p[6];
+                    }
+                    sp += p.shift() + p;
+                }
+                subpaths.end = sp;
+                point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
+                point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
+                return point;
+            };
+        };
+    var getTotalLength = getLengthFactory(1),
+        getPointAtLength = getLengthFactory(),
+        getSubpathsAtLength = getLengthFactory(0, 1);
+    /*\
+     * Raphael.getTotalLength
+     [ method ]
+     **
+     * Returns length of the given path in pixels.
+     **
+     > Parameters
+     **
+     - path (string) SVG path string.
+     **
+     = (number) length.
+     \*/
+    R.getTotalLength = getTotalLength;
+    /*\
+     * Raphael.getPointAtLength
+     [ method ]
+     **
+     * Return coordinates of the point located at the given length on the given path.
+     **
+     > Parameters
+     **
+     - path (string) SVG path string
+     - length (number)
+     **
+     = (object) representation of the point:
+     o {
+     o     x: (number) x coordinate
+     o     y: (number) y coordinate
+     o     alpha: (number) angle of derivative
+     o }
+     \*/
+    R.getPointAtLength = getPointAtLength;
+    /*\
+     * Raphael.getSubpath
+     [ method ]
+     **
+     * Return subpath of a given path from given length to given length.
+     **
+     > Parameters
+     **
+     - path (string) SVG path string
+     - from (number) position of the start of the segment
+     - to (number) position of the end of the segment
+     **
+     = (string) pathstring for the segment
+     \*/
+    R.getSubpath = function (path, from, to) {
+        if (this.getTotalLength(path) - to < 1e-6) {
+            return getSubpathsAtLength(path, from).end;
+        }
+        var a = getSubpathsAtLength(path, to, 1);
+        return from ? getSubpathsAtLength(a, from).end : a;
+    };
+    /*\
+     * Element.getTotalLength
+     [ method ]
+     **
+     * Returns length of the path in pixels. Only works for element of “path” type.
+     = (number) length.
+     \*/
+    elproto.getTotalLength = function () {
+        var path = this.getPath();
+        if (!path) {
+            return;
+        }
+
+        if (this.node.getTotalLength) {
+            return this.node.getTotalLength();
+        }
+
+        return getTotalLength(path);
+    };
+    /*\
+     * Element.getPointAtLength
+     [ method ]
+     **
+     * Return coordinates of the point located at the given length on the given path. Only works for element of “path” type.
+     **
+     > Parameters
+     **
+     - length (number)
+     **
+     = (object) representation of the point:
+     o {
+     o     x: (number) x coordinate
+     o     y: (number) y coordinate
+     o     alpha: (number) angle of derivative
+     o }
+     \*/
+    elproto.getPointAtLength = function (length) {
+        var path = this.getPath();
+        if (!path) {
+            return;
+        }
+
+        return getPointAtLength(path, length);
+    };
+    /*\
+     * Element.getPath
+     [ method ]
+     **
+     * Returns path of the element. Only works for elements of “path” type and simple elements like circle.
+     = (object) path
+     **
+     \*/
+    elproto.getPath = function () {
+        var path,
+            getPath = R._getPath[this.type];
+
+        if (this.type == "text" || this.type == "set") {
+            return;
+        }
+
+        if (getPath) {
+            path = getPath(this);
+        }
+
+        return path;
+    };
+    /*\
+     * Element.getSubpath
+     [ method ]
+     **
+     * Return subpath of a given element from given length to given length. Only works for element of “path” type.
+     **
+     > Parameters
+     **
+     - from (number) position of the start of the segment
+     - to (number) position of the end of the segment
+     **
+     = (string) pathstring for the segment
+     \*/
+    elproto.getSubpath = function (from, to) {
+        var path = this.getPath();
+        if (!path) {
+            return;
+        }
+
+        return R.getSubpath(path, from, to);
+    };
+    /*\
+     * Raphael.easing_formulas
+     [ property ]
+     **
+     * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing:
+     # <ul>
+     #     <li>“linear”</li>
+     #     <li>“&lt;” or “easeIn” or “ease-in”</li>
+     #     <li>“>” or “easeOut” or “ease-out”</li>
+     #     <li>“&lt;>” or “easeInOut” or “ease-in-out”</li>
+     #     <li>“backIn” or “back-in”</li>
+     #     <li>“backOut” or “back-out”</li>
+     #     <li>“elastic”</li>
+     #     <li>“bounce”</li>
+     # </ul>
+     # <p>See also <a href="http://raphaeljs.com/easing.html">Easing demo</a>.</p>
+     \*/
+    var ef = R.easing_formulas = {
+        linear: function (n) {
+            return n;
+        },
+        "<": function (n) {
+            return pow(n, 1.7);
+        },
+        ">": function (n) {
+            return pow(n, .48);
+        },
+        "<>": function (n) {
+            var q = .48 - n / 1.04,
+                Q = math.sqrt(.1734 + q * q),
+                x = Q - q,
+                X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
+                y = -Q - q,
+                Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
+                t = X + Y + .5;
+            return (1 - t) * 3 * t * t + t * t * t;
+        },
+        backIn: function (n) {
+            var s = 1.70158;
+            return n * n * ((s + 1) * n - s);
+        },
+        backOut: function (n) {
+            n = n - 1;
+            var s = 1.70158;
+            return n * n * ((s + 1) * n + s) + 1;
+        },
+        elastic: function (n) {
+            if (n == !!n) {
+                return n;
+            }
+            return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
+        },
+        bounce: function (n) {
+            var s = 7.5625,
+                p = 2.75,
+                l;
+            if (n < (1 / p)) {
+                l = s * n * n;
+            } else {
+                if (n < (2 / p)) {
+                    n -= (1.5 / p);
+                    l = s * n * n + .75;
+                } else {
+                    if (n < (2.5 / p)) {
+                        n -= (2.25 / p);
+                        l = s * n * n + .9375;
+                    } else {
+                        n -= (2.625 / p);
+                        l = s * n * n + .984375;
+                    }
+                }
+            }
+            return l;
+        }
+    };
+    ef.easeIn = ef["ease-in"] = ef["<"];
+    ef.easeOut = ef["ease-out"] = ef[">"];
+    ef.easeInOut = ef["ease-in-out"] = ef["<>"];
+    ef["back-in"] = ef.backIn;
+    ef["back-out"] = ef.backOut;
+
+    var animationElements = [],
+        requestAnimFrame = window.requestAnimationFrame       ||
+            window.webkitRequestAnimationFrame ||
+            window.mozRequestAnimationFrame    ||
+            window.oRequestAnimationFrame      ||
+            window.msRequestAnimationFrame     ||
+            function (callback) {
+                setTimeout(callback, 16);
+            },
+        animation = function () {
+            var Now = +new Date,
+                l = 0;
+            for (; l < animationElements.length; l++) {
+                var e = animationElements[l];
+                if (e.el.removed || e.paused) {
+                    continue;
+                }
+                var time = Now - e.start,
+                    ms = e.ms,
+                    easing = e.easing,
+                    from = e.from,
+                    diff = e.diff,
+                    to = e.to,
+                    t = e.t,
+                    that = e.el,
+                    set = {},
+                    now,
+                    init = {},
+                    key;
+                if (e.initstatus) {
+                    time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
+                    e.status = e.initstatus;
+                    delete e.initstatus;
+                    e.stop && animationElements.splice(l--, 1);
+                } else {
+                    e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
+                }
+                if (time < 0) {
+                    continue;
+                }
+                if (time < ms) {
+                    var pos = easing(time / ms);
+                    for (var attr in from) if (from[has](attr)) {
+                        switch (availableAnimAttrs[attr]) {
+                            case nu:
+                                now = +from[attr] + pos * ms * diff[attr];
+                                break;
+                            case "colour":
+                                now = "rgb(" + [
+                                        upto255(round(from[attr].r + pos * ms * diff[attr].r)),
+                                        upto255(round(from[attr].g + pos * ms * diff[attr].g)),
+                                        upto255(round(from[attr].b + pos * ms * diff[attr].b))
+                                    ].join(",") + ")";
+                                break;
+                            case "path":
+                                now = [];
+                                for (var i = 0, ii = from[attr].length; i < ii; i++) {
+                                    now[i] = [from[attr][i][0]];
+                                    for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+                                        now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];
+                                    }
+                                    now[i] = now[i].join(S);
+                                }
+                                now = now.join(S);
+                                break;
+                            case "transform":
+                                if (diff[attr].real) {
+                                    now = [];
+                                    for (i = 0, ii = from[attr].length; i < ii; i++) {
+                                        now[i] = [from[attr][i][0]];
+                                        for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+                                            now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
+                                        }
+                                    }
+                                } else {
+                                    var get = function (i) {
+                                        return +from[attr][i] + pos * ms * diff[attr][i];
+                                    };
+                                    // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
+                                    now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
+                                }
+                                break;
+                            case "csv":
+                                if (attr == "clip-rect") {
+                                    now = [];
+                                    i = 4;
+                                    while (i--) {
+                                        now[i] = +from[attr][i] + pos * ms * diff[attr][i];
+                                    }
+                                }
+                                break;
+                            default:
+                                var from2 = [][concat](from[attr]);
+                                now = [];
+                                i = that.paper.customAttributes[attr].length;
+                                while (i--) {
+                                    now[i] = +from2[i] + pos * ms * diff[attr][i];
+                                }
+                                break;
+                        }
+                        set[attr] = now;
+                    }
+                    that.attr(set);
+                    (function (id, that, anim) {
+                        setTimeout(function () {
+                            eve("raphael.anim.frame." + id, that, anim);
+                        });
+                    })(that.id, that, e.anim);
+                } else {
+                    (function(f, el, a) {
+                        setTimeout(function() {
+                            eve("raphael.anim.frame." + el.id, el, a);
+                            eve("raphael.anim.finish." + el.id, el, a);
+                            R.is(f, "function") && f.call(el);
+                        });
+                    })(e.callback, that, e.anim);
+                    that.attr(to);
+                    animationElements.splice(l--, 1);
+                    if (e.repeat > 1 && !e.next) {
+                        for (key in to) if (to[has](key)) {
+                            init[key] = e.totalOrigin[key];
+                        }
+                        e.el.attr(init);
+                        runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
+                    }
+                    if (e.next && !e.stop) {
+                        runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
+                    }
+                }
+            }
+            animationElements.length && requestAnimFrame(animation);
+        },
+        upto255 = function (color) {
+            return color > 255 ? 255 : color < 0 ? 0 : color;
+        };
+    /*\
+     * Element.animateWith
+     [ method ]
+     **
+     * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element.
+     **
+     > Parameters
+     **
+     - el (object) element to sync with
+     - anim (object) animation to sync with
+     - params (object) #optional final attributes for the element, see also @Element.attr
+     - ms (number) #optional number of milliseconds for animation to run
+     - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic&#x2010;bezier(XX,&#160;XX,&#160;XX,&#160;XX)`
+     - callback (function) #optional callback function. Will be called at the end of animation.
+     * or
+     - element (object) element to sync with
+     - anim (object) animation to sync with
+     - animation (object) #optional animation object, see @Raphael.animation
+     **
+     = (object) original element
+     \*/
+    elproto.animateWith = function (el, anim, params, ms, easing, callback) {
+        var element = this;
+        if (element.removed) {
+            callback && callback.call(element);
+            return element;
+        }
+        var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback),
+            x, y;
+        runAnimation(a, element, a.percents[0], null, element.attr());
+        for (var i = 0, ii = animationElements.length; i < ii; i++) {
+            if (animationElements[i].anim == anim && animationElements[i].el == el) {
+                animationElements[ii - 1].start = animationElements[i].start;
+                break;
+            }
+        }
+        return element;
+        //
+        //
+        // var a = params ? R.animation(params, ms, easing, callback) : anim,
+        //     status = element.status(anim);
+        // return this.animate(a).status(a, status * anim.ms / a.ms);
+    };
+    function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
+        var cx = 3 * p1x,
+            bx = 3 * (p2x - p1x) - cx,
+            ax = 1 - cx - bx,
+            cy = 3 * p1y,
+            by = 3 * (p2y - p1y) - cy,
+            ay = 1 - cy - by;
+        function sampleCurveX(t) {
+            return ((ax * t + bx) * t + cx) * t;
+        }
+        function solve(x, epsilon) {
+            var t = solveCurveX(x, epsilon);
+            return ((ay * t + by) * t + cy) * t;
+        }
+        function solveCurveX(x, epsilon) {
+            var t0, t1, t2, x2, d2, i;
+            for(t2 = x, i = 0; i < 8; i++) {
+                x2 = sampleCurveX(t2) - x;
+                if (abs(x2) < epsilon) {
+                    return t2;
+                }
+                d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
+                if (abs(d2) < 1e-6) {
+                    break;
+                }
+                t2 = t2 - x2 / d2;
+            }
+            t0 = 0;
+            t1 = 1;
+            t2 = x;
+            if (t2 < t0) {
+                return t0;
+            }
+            if (t2 > t1) {
+                return t1;
+            }
+            while (t0 < t1) {
+                x2 = sampleCurveX(t2);
+                if (abs(x2 - x) < epsilon) {
+                    return t2;
+                }
+                if (x > x2) {
+                    t0 = t2;
+                } else {
+                    t1 = t2;
+                }
+                t2 = (t1 - t0) / 2 + t0;
+            }
+            return t2;
+        }
+        return solve(t, 1 / (200 * duration));
+    }
+    elproto.onAnimation = function (f) {
+        f ? eve.on("raphael.anim.frame." + this.id, f) : eve.unbind("raphael.anim.frame." + this.id);
+        return this;
+    };
+    function Animation(anim, ms) {
+        var percents = [],
+            newAnim = {};
+        this.ms = ms;
+        this.times = 1;
+        if (anim) {
+            for (var attr in anim) if (anim[has](attr)) {
+                newAnim[toFloat(attr)] = anim[attr];
+                percents.push(toFloat(attr));
+            }
+            percents.sort(sortByNumber);
+        }
+        this.anim = newAnim;
+        this.top = percents[percents.length - 1];
+        this.percents = percents;
+    }
+    /*\
+     * Animation.delay
+     [ method ]
+     **
+     * Creates a copy of existing animation object with given delay.
+     **
+     > Parameters
+     **
+     - delay (number) number of ms to pass between animation start and actual animation
+     **
+     = (object) new altered Animation object
+     | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3);
+     | circle1.animate(anim); // run the given animation immediately
+     | circle2.animate(anim.delay(500)); // run the given animation after 500 ms
+     \*/
+    Animation.prototype.delay = function (delay) {
+        var a = new Animation(this.anim, this.ms);
+        a.times = this.times;
+        a.del = +delay || 0;
+        return a;
+    };
+    /*\
+     * Animation.repeat
+     [ method ]
+     **
+     * Creates a copy of existing animation object with given repetition.
+     **
+     > Parameters
+     **
+     - repeat (number) number iterations of animation. For infinite animation pass `Infinity`
+     **
+     = (object) new altered Animation object
+     \*/
+    Animation.prototype.repeat = function (times) {
+        var a = new Animation(this.anim, this.ms);
+        a.del = this.del;
+        a.times = math.floor(mmax(times, 0)) || 1;
+        return a;
+    };
+    function runAnimation(anim, element, percent, status, totalOrigin, times) {
+        percent = toFloat(percent);
+        var params,
+            isInAnim,
+            isInAnimSet,
+            percents = [],
+            next,
+            prev,
+            timestamp,
+            ms = anim.ms,
+            from = {},
+            to = {},
+            diff = {};
+        if (status) {
+            for (i = 0, ii = animationElements.length; i < ii; i++) {
+                var e = animationElements[i];
+                if (e.el.id == element.id && e.anim == anim) {
+                    if (e.percent != percent) {
+                        animationElements.splice(i, 1);
+                        isInAnimSet = 1;
+                    } else {
+                        isInAnim = e;
+                    }
+                    element.attr(e.totalOrigin);
+                    break;
+                }
+            }
+        } else {
+            status = +to; // NaN
+        }
+        for (var i = 0, ii = anim.percents.length; i < ii; i++) {
+            if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
+                percent = anim.percents[i];
+                prev = anim.percents[i - 1] || 0;
+                ms = ms / anim.top * (percent - prev);
+                next = anim.percents[i + 1];
+                params = anim.anim[percent];
+                break;
+            } else if (status) {
+                element.attr(anim.anim[anim.percents[i]]);
+            }
+        }
+        if (!params) {
+            return;
+        }
+        if (!isInAnim) {
+            for (var attr in params) if (params[has](attr)) {
+                if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) {
+                    from[attr] = element.attr(attr);
+                    (from[attr] == null) && (from[attr] = availableAttrs[attr]);
+                    to[attr] = params[attr];
+                    switch (availableAnimAttrs[attr]) {
+                        case nu:
+                            diff[attr] = (to[attr] - from[attr]) / ms;
+                            break;
+                        case "colour":
+                            from[attr] = R.getRGB(from[attr]);
+                            var toColour = R.getRGB(to[attr]);
+                            diff[attr] = {
+                                r: (toColour.r - from[attr].r) / ms,
+                                g: (toColour.g - from[attr].g) / ms,
+                                b: (toColour.b - from[attr].b) / ms
+                            };
+                            break;
+                        case "path":
+                            var pathes = path2curve(from[attr], to[attr]),
+                                toPath = pathes[1];
+                            from[attr] = pathes[0];
+                            diff[attr] = [];
+                            for (i = 0, ii = from[attr].length; i < ii; i++) {
+                                diff[attr][i] = [0];
+                                for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
+                                    diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
+                                }
+                            }
+                            break;
+                        case "transform":
+                            var _ = element._,
+                                eq = equaliseTransform(_[attr], to[attr]);
+                            if (eq) {
+                                from[attr] = eq.from;
+                                to[attr] = eq.to;
+                                diff[attr] = [];
+                                diff[attr].real = true;
+                                for (i = 0, ii = from[attr].length; i < ii; i++) {
+                                    diff[attr][i] = [from[attr][i][0]];
+                                    for (j = 1, jj = from[attr][i].length; j < jj; j++) {
+                                        diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
+                                    }
+                                }
+                            } else {
+                                var m = (element.matrix || new Matrix),
+                                    to2 = {
+                                        _: {transform: _.transform},
+                                        getBBox: function () {
+                                            return element.getBBox(1);
+                                        }
+                                    };
+                                from[attr] = [
+                                    m.a,
+                                    m.b,
+                                    m.c,
+                                    m.d,
+                                    m.e,
+                                    m.f
+                                ];
+                                extractTransform(to2, to[attr]);
+                                to[attr] = to2._.transform;
+                                diff[attr] = [
+                                    (to2.matrix.a - m.a) / ms,
+                                    (to2.matrix.b - m.b) / ms,
+                                    (to2.matrix.c - m.c) / ms,
+                                    (to2.matrix.d - m.d) / ms,
+                                    (to2.matrix.e - m.e) / ms,
+                                    (to2.matrix.f - m.f) / ms
+                                ];
+                                // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
+                                // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
+                                // extractTransform(to2, to[attr]);
+                                // diff[attr] = [
+                                //     (to2._.sx - _.sx) / ms,
+                                //     (to2._.sy - _.sy) / ms,
+                                //     (to2._.deg - _.deg) / ms,
+                                //     (to2._.dx - _.dx) / ms,
+                                //     (to2._.dy - _.dy) / ms
+                                // ];
+                            }
+                            break;
+                        case "csv":
+                            var values = Str(params[attr])[split](separator),
+                                from2 = Str(from[attr])[split](separator);
+                            if (attr == "clip-rect") {
+                                from[attr] = from2;
+                                diff[attr] = [];
+                                i = from2.length;
+                                while (i--) {
+                                    diff[attr][i] = (values[i] - from[attr][i]) / ms;
+                                }
+                            }
+                            to[attr] = values;
+                            break;
+                        default:
+                            values = [][concat](params[attr]);
+                            from2 = [][concat](from[attr]);
+                            diff[attr] = [];
+                            i = element.paper.customAttributes[attr].length;
+                            while (i--) {
+                                diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
+                            }
+                            break;
+                    }
+                }
+            }
+            var easing = params.easing,
+                easyeasy = R.easing_formulas[easing];
+            if (!easyeasy) {
+                easyeasy = Str(easing).match(bezierrg);
+                if (easyeasy && easyeasy.length == 5) {
+                    var curve = easyeasy;
+                    easyeasy = function (t) {
+                        return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
+                    };
+                } else {
+                    easyeasy = pipe;
+                }
+            }
+            timestamp = params.start || anim.start || +new Date;
+            e = {
+                anim: anim,
+                percent: percent,
+                timestamp: timestamp,
+                start: timestamp + (anim.del || 0),
+                status: 0,
+                initstatus: status || 0,
+                stop: false,
+                ms: ms,
+                easing: easyeasy,
+                from: from,
+                diff: diff,
+                to: to,
+                el: element,
+                callback: params.callback,
+                prev: prev,
+                next: next,
+                repeat: times || anim.times,
+                origin: element.attr(),
+                totalOrigin: totalOrigin
+            };
+            animationElements.push(e);
+            if (status && !isInAnim && !isInAnimSet) {
+                e.stop = true;
+                e.start = new Date - ms * status;
+                if (animationElements.length == 1) {
+                    return animation();
+                }
+            }
+            if (isInAnimSet) {
+                e.start = new Date - e.ms * status;
+            }
+            animationElements.length == 1 && requestAnimFrame(animation);
+        } else {
+            isInAnim.initstatus = status;
+            isInAnim.start = new Date - isInAnim.ms * status;
+        }
+        eve("raphael.anim.start." + element.id, element, anim);
+    }
+    /*\
+     * Raphael.animation
+     [ method ]
+     **
+     * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods.
+     * See also @Animation.delay and @Animation.repeat methods.
+     **
+     > Parameters
+     **
+     - params (object) final attributes for the element, see also @Element.attr
+     - ms (number) number of milliseconds for animation to run
+     - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic&#x2010;bezier(XX,&#160;XX,&#160;XX,&#160;XX)`
+     - callback (function) #optional callback function. Will be called at the end of animation.
+     **
+     = (object) @Animation
+     \*/
+    R.animation = function (params, ms, easing, callback) {
+        if (params instanceof Animation) {
+            return params;
+        }
+        if (R.is(easing, "function") || !easing) {
+            callback = callback || easing || null;
+            easing = null;
+        }
+        params = Object(params);
+        ms = +ms || 0;
+        var p = {},
+            json,
+            attr;
+        for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
+            json = true;
+            p[attr] = params[attr];
+        }
+        if (!json) {
+            // if percent-like syntax is used and end-of-all animation callback used
+            if(callback){
+                // find the last one
+                var lastKey = 0;
+                for(var i in params){
+                    var percent = toInt(i);
+                    if(params[has](i) && percent > lastKey){
+                        lastKey = percent;
+                    }
+                }
+                lastKey += '%';
+                // if already defined callback in the last keyframe, skip
+                !params[lastKey].callback && (params[lastKey].callback = callback);
+            }
+            return new Animation(params, ms);
+        } else {
+            easing && (p.easing = easing);
+            callback && (p.callback = callback);
+            return new Animation({100: p}, ms);
+        }
+    };
+    /*\
+     * Element.animate
+     [ method ]
+     **
+     * Creates and starts animation for given element.
+     **
+     > Parameters
+     **
+     - params (object) final attributes for the element, see also @Element.attr
+     - ms (number) number of milliseconds for animation to run
+     - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic&#x2010;bezier(XX,&#160;XX,&#160;XX,&#160;XX)`
+     - callback (function) #optional callback function. Will be called at the end of animation.
+     * or
+     - animation (object) animation object, see @Raphael.animation
+     **
+     = (object) original element
+     \*/
+    elproto.animate = function (params, ms, easing, callback) {
+        var element = this;
+        if (element.removed) {
+            callback && callback.call(element);
+            return element;
+        }
+        var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
+        runAnimation(anim, element, anim.percents[0], null, element.attr());
+        return element;
+    };
+    /*\
+     * Element.setTime
+     [ method ]
+     **
+     * Sets the status of animation of the element in milliseconds. Similar to @Element.status method.
+     **
+     > Parameters
+     **
+     - anim (object) animation object
+     - value (number) number of milliseconds from the beginning of the animation
+     **
+     = (object) original element if `value` is specified
+     * Note, that during animation following events are triggered:
+     *
+     * On each animation frame event `anim.frame.<id>`, on start `anim.start.<id>` and on end `anim.finish.<id>`.
+     \*/
+    elproto.setTime = function (anim, value) {
+        if (anim && value != null) {
+            this.status(anim, mmin(value, anim.ms) / anim.ms);
+        }
+        return this;
+    };
+    /*\
+     * Element.status
+     [ method ]
+     **
+     * Gets or sets the status of animation of the element.
+     **
+     > Parameters
+     **
+     - anim (object) #optional animation object
+     - value (number) #optional 0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position.
+     **
+     = (number) status
+     * or
+     = (array) status if `anim` is not specified. Array of objects in format:
+     o {
+     o     anim: (object) animation object
+     o     status: (number) status
+     o }
+     * or
+     = (object) original element if `value` is specified
+     \*/
+    elproto.status = function (anim, value) {
+        var out = [],
+            i = 0,
+            len,
+            e;
+        if (value != null) {
+            runAnimation(anim, this, -1, mmin(value, 1));
+            return this;
+        } else {
+            len = animationElements.length;
+            for (; i < len; i++) {
+                e = animationElements[i];
+                if (e.el.id == this.id && (!anim || e.anim == anim)) {
+                    if (anim) {
+                        return e.status;
+                    }
+                    out.push({
+                        anim: e.anim,
+                        status: e.status
+                    });
+                }
+            }
+            if (anim) {
+                return 0;
+            }
+            return out;
+        }
+    };
+    /*\
+     * Element.pause
+     [ method ]
+     **
+     * Stops animation of the element with ability to resume it later on.
+     **
+     > Parameters
+     **
+     - anim (object) #optional animation object
+     **
+     = (object) original element
+     \*/
+    elproto.pause = function (anim) {
+        for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+            if (eve("raphael.anim.pause." + this.id, this, animationElements[i].anim) !== false) {
+                animationElements[i].paused = true;
+            }
+        }
+        return this;
+    };
+    /*\
+     * Element.resume
+     [ method ]
+     **
+     * Resumes animation if it was paused with @Element.pause method.
+     **
+     > Parameters
+     **
+     - anim (object) #optional animation object
+     **
+     = (object) original element
+     \*/
+    elproto.resume = function (anim) {
+        for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+            var e = animationElements[i];
+            if (eve("raphael.anim.resume." + this.id, this, e.anim) !== false) {
+                delete e.paused;
+                this.status(e.anim, e.status);
+            }
+        }
+        return this;
+    };
+    /*\
+     * Element.stop
+     [ method ]
+     **
+     * Stops animation of the element.
+     **
+     > Parameters
+     **
+     - anim (object) #optional animation object
+     **
+     = (object) original element
+     \*/
+    elproto.stop = function (anim) {
+        for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
+            if (eve("raphael.anim.stop." + this.id, this, animationElements[i].anim) !== false) {
+                animationElements.splice(i--, 1);
+            }
+        }
+        return this;
+    };
+    function stopAnimation(paper) {
+        for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.paper == paper) {
+            animationElements.splice(i--, 1);
+        }
+    }
+    eve.on("raphael.remove", stopAnimation);
+    eve.on("raphael.clear", stopAnimation);
+    elproto.toString = function () {
+        return "Rapha\xebl\u2019s object";
+    };
+
+    // Set
+    var Set = function (items) {
+            this.items = [];
+            this.length = 0;
+            this.type = "set";
+            if (items) {
+                for (var i = 0, ii = items.length; i < ii; i++) {
+                    if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
+                        this[this.items.length] = this.items[this.items.length] = items[i];
+                        this.length++;
+                    }
+                }
+            }
+        },
+        setproto = Set.prototype;
+    /*\
+     * Set.push
+     [ method ]
+     **
+     * Adds each argument to the current set.
+     = (object) original element
+     \*/
+    setproto.push = function () {
+        var item,
+            len;
+        for (var i = 0, ii = arguments.length; i < ii; i++) {
+            item = arguments[i];
+            if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
+                len = this.items.length;
+                this[len] = this.items[len] = item;
+                this.length++;
+            }
+        }
+        return this;
+    };
+    /*\
+     * Set.pop
+     [ method ]
+     **
+     * Removes last element and returns it.
+     = (object) element
+     \*/
+    setproto.pop = function () {
+        this.length && delete this[this.length--];
+        return this.items.pop();
+    };
+    /*\
+     * Set.forEach
+     [ method ]
+     **
+     * Executes given function for each element in the set.
+     *
+     * If function returns `false` it will stop loop running.
+     **
+     > Parameters
+     **
+     - callback (function) function to run
+     - thisArg (object) context object for the callback
+     = (object) Set object
+     \*/
+    setproto.forEach = function (callback, thisArg) {
+        for (var i = 0, ii = this.items.length; i < ii; i++) {
+            if (callback.call(thisArg, this.items[i], i) === false) {
+                return this;
+            }
+        }
+        return this;
+    };
+    for (var method in elproto) if (elproto[has](method)) {
+        setproto[method] = (function (methodname) {
+            return function () {
+                var arg = arguments;
+                return this.forEach(function (el) {
+                    el[methodname][apply](el, arg);
+                });
+            };
+        })(method);
+    }
+    setproto.attr = function (name, value) {
+        if (name && R.is(name, array) && R.is(name[0], "object")) {
+            for (var j = 0, jj = name.length; j < jj; j++) {
+                this.items[j].attr(name[j]);
+            }
+        } else {
+            for (var i = 0, ii = this.items.length; i < ii; i++) {
+                this.items[i].attr(name, value);
+            }
+        }
+        return this;
+    };
+    /*\
+     * Set.clear
+     [ method ]
+     **
+     * Removes all elements from the set
+     \*/
+    setproto.clear = function () {
+        while (this.length) {
+            this.pop();
+        }
+    };
+    /*\
+     * Set.splice
+     [ method ]
+     **
+     * Removes given element from the set
+     **
+     > Parameters
+     **
+     - index (number) position of the deletion
+     - count (number) number of element to remove
+     - insertion… (object) #optional elements to insert
+     = (object) set elements that were deleted
+     \*/
+    setproto.splice = function (index, count, insertion) {
+        index = index < 0 ? mmax(this.length + index, 0) : index;
+        count = mmax(0, mmin(this.length - index, count));
+        var tail = [],
+            todel = [],
+            args = [],
+            i;
+        for (i = 2; i < arguments.length; i++) {
+            args.push(arguments[i]);
+        }
+        for (i = 0; i < count; i++) {
+            todel.push(this[index + i]);
+        }
+        for (; i < this.length - index; i++) {
+            tail.push(this[index + i]);
+        }
+        var arglen = args.length;
+        for (i = 0; i < arglen + tail.length; i++) {
+            this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
+        }
+        i = this.items.length = this.length -= count - arglen;
+        while (this[i]) {
+            delete this[i++];
+        }
+        return new Set(todel);
+    };
+    /*\
+     * Set.exclude
+     [ method ]
+     **
+     * Removes given element from the set
+     **
+     > Parameters
+     **
+     - element (object) element to remove
+     = (boolean) `true` if object was found & removed from the set
+     \*/
+    setproto.exclude = function (el) {
+        for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
+            this.splice(i, 1);
+            return true;
+        }
+    };
+    setproto.animate = function (params, ms, easing, callback) {
+        (R.is(easing, "function") || !easing) && (callback = easing || null);
+        var len = this.items.length,
+            i = len,
+            item,
+            set = this,
+            collector;
+        if (!len) {
+            return this;
+        }
+        callback && (collector = function () {
+            !--len && callback.call(set);
+        });
+        easing = R.is(easing, string) ? easing : collector;
+        var anim = R.animation(params, ms, easing, collector);
+        item = this.items[--i].animate(anim);
+        while (i--) {
+            this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim);
+            (this.items[i] && !this.items[i].removed) || len--;
+        }
+        return this;
+    };
+    setproto.insertAfter = function (el) {
+        var i = this.items.length;
+        while (i--) {
+            this.items[i].insertAfter(el);
+        }
+        return this;
+    };
+    setproto.getBBox = function () {
+        var x = [],
+            y = [],
+            x2 = [],
+            y2 = [];
+        for (var i = this.items.length; i--;) if (!this.items[i].removed) {
+            var box = this.items[i].getBBox();
+            x.push(box.x);
+            y.push(box.y);
+            x2.push(box.x + box.width);
+            y2.push(box.y + box.height);
+        }
+        x = mmin[apply](0, x);
+        y = mmin[apply](0, y);
+        x2 = mmax[apply](0, x2);
+        y2 = mmax[apply](0, y2);
+        return {
+            x: x,
+            y: y,
+            x2: x2,
+            y2: y2,
+            width: x2 - x,
+            height: y2 - y
+        };
+    };
+    setproto.clone = function (s) {
+        s = this.paper.set();
+        for (var i = 0, ii = this.items.length; i < ii; i++) {
+            s.push(this.items[i].clone());
+        }
+        return s;
+    };
+    setproto.toString = function () {
+        return "Rapha\xebl\u2018s set";
+    };
+
+    setproto.glow = function(glowConfig) {
+        var ret = this.paper.set();
+        this.forEach(function(shape, index){
+            var g = shape.glow(glowConfig);
+            if(g != null){
+                g.forEach(function(shape2, index2){
+                    ret.push(shape2);
+                });
+            }
+        });
+        return ret;
+    };
+
+
+    /*\
+     * Set.isPointInside
+     [ method ]
+     **
+     * Determine if given point is inside this set’s elements
+     **
+     > Parameters
+     **
+     - x (number) x coordinate of the point
+     - y (number) y coordinate of the point
+     = (boolean) `true` if point is inside any of the set's elements
+     \*/
+    setproto.isPointInside = function (x, y) {
+        var isPointInside = false;
+        this.forEach(function (el) {
+            if (el.isPointInside(x, y)) {
+                isPointInside = true;
+                return false; // stop loop
+            }
+        });
+        return isPointInside;
+    };
+
+    /*\
+     * Raphael.registerFont
+     [ method ]
+     **
+     * Adds given font to the registered set of font for Raphaël. Should be used as an internal call from within Cufón’s font file.
+     * Returns original parameter, so it could be used with chaining.
+     # <a href="http://wiki.github.com/sorccu/cufon/about">More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.</a>
+     **
+     > Parameters
+     **
+     - font (object) the font to register
+     = (object) the font you passed in
+     > Usage
+     | Cufon.registerFont(Raphael.registerFont({…}));
+     \*/
+    R.registerFont = function (font) {
+        if (!font.face) {
+            return font;
+        }
+        this.fonts = this.fonts || {};
+        var fontcopy = {
+                w: font.w,
+                face: {},
+                glyphs: {}
+            },
+            family = font.face["font-family"];
+        for (var prop in font.face) if (font.face[has](prop)) {
+            fontcopy.face[prop] = font.face[prop];
+        }
+        if (this.fonts[family]) {
+            this.fonts[family].push(fontcopy);
+        } else {
+            this.fonts[family] = [fontcopy];
+        }
+        if (!font.svg) {
+            fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
+            for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
+                var path = font.glyphs[glyph];
+                fontcopy.glyphs[glyph] = {
+                    w: path.w,
+                    k: {},
+                    d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) {
+                        return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
+                    }) + "z"
+                };
+                if (path.k) {
+                    for (var k in path.k) if (path[has](k)) {
+                        fontcopy.glyphs[glyph].k[k] = path.k[k];
+                    }
+                }
+            }
+        }
+        return font;
+    };
+    /*\
+     * Paper.getFont
+     [ method ]
+     **
+     * Finds font object in the registered font by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
+     **
+     > Parameters
+     **
+     - family (string) font family name or any word from it
+     - weight (string) #optional font weight
+     - style (string) #optional font style
+     - stretch (string) #optional font stretch
+     = (object) the font object
+     > Usage
+     | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
+     \*/
+    paperproto.getFont = function (family, weight, style, stretch) {
+        stretch = stretch || "normal";
+        style = style || "normal";
+        weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
+        if (!R.fonts) {
+            return;
+        }
+        var font = R.fonts[family];
+        if (!font) {
+            var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
+            for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
+                if (name.test(fontName)) {
+                    font = R.fonts[fontName];
+                    break;
+                }
+            }
+        }
+        var thefont;
+        if (font) {
+            for (var i = 0, ii = font.length; i < ii; i++) {
+                thefont = font[i];
+                if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
+                    break;
+                }
+            }
+        }
+        return thefont;
+    };
+    /*\
+     * Paper.print
+     [ method ]
+     **
+     * Creates path that represent given text written using given font at given position with given size.
+     * Result of the method is path element that contains whole text as a separate path.
+     **
+     > Parameters
+     **
+     - x (number) x position of the text
+     - y (number) y position of the text
+     - string (string) text to print
+     - font (object) font object, see @Paper.getFont
+     - size (number) #optional size of the font, default is `16`
+     - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"`
+     - letter_spacing (number) #optional number in range `-1..1`, default is `0`
+     - line_spacing (number) #optional number in range `1..3`, default is `1`
+     = (object) resulting path element, which consist of all letters
+     > Usage
+     | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"});
+     \*/
+    paperproto.print = function (x, y, string, font, size, origin, letter_spacing, line_spacing) {
+        origin = origin || "middle"; // baseline|middle
+        letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
+        line_spacing = mmax(mmin(line_spacing || 1, 3), 1);
+        var letters = Str(string)[split](E),
+            shift = 0,
+            notfirst = 0,
+            path = E,
+            scale;
+        R.is(font, "string") && (font = this.getFont(font));
+        if (font) {
+            scale = (size || 16) / font.face["units-per-em"];
+            var bb = font.face.bbox[split](separator),
+                top = +bb[0],
+                lineHeight = bb[3] - bb[1],
+                shifty = 0,
+                height = +bb[1] + (origin == "baseline" ? lineHeight + (+font.face.descent) : lineHeight / 2);
+            for (var i = 0, ii = letters.length; i < ii; i++) {
+                if (letters[i] == "\n") {
+                    shift = 0;
+                    curr = 0;
+                    notfirst = 0;
+                    shifty += lineHeight * line_spacing;
+                } else {
+                    var prev = notfirst && font.glyphs[letters[i - 1]] || {},
+                        curr = font.glyphs[letters[i]];
+                    shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
+                    notfirst = 1;
+                }
+                if (curr && curr.d) {
+                    path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
+                }
+            }
+        }
+        return this.path(path).attr({
+            fill: "#000",
+            stroke: "none"
+        });
+    };
+
+    /*\
+     * Paper.add
+     [ method ]
+     **
+     * Imports elements in JSON array in format `{type: type, <attributes>}`
+     **
+     > Parameters
+     **
+     - json (array)
+     = (object) resulting set of imported elements
+     > Usage
+     | paper.add([
+     |     {
+     |         type: "circle",
+     |         cx: 10,
+     |         cy: 10,
+     |         r: 5
+     |     },
+     |     {
+     |         type: "rect",
+     |         x: 10,
+     |         y: 10,
+     |         width: 10,
+     |         height: 10,
+     |         fill: "#fc0"
+     |     }
+     | ]);
+     \*/
+    paperproto.add = function (json) {
+        if (R.is(json, "array")) {
+            var res = this.set(),
+                i = 0,
+                ii = json.length,
+                j;
+            for (; i < ii; i++) {
+                j = json[i] || {};
+                elements[has](j.type) && res.push(this[j.type]().attr(j));
+            }
+        }
+        return res;
+    };
+
+    /*\
+     * Raphael.format
+     [ method ]
+     **
+     * Simple format function. Replaces construction of type “`{<number>}`” to the corresponding argument.
+     **
+     > Parameters
+     **
+     - token (string) string to format
+     - … (string) rest of arguments will be treated as parameters for replacement
+     = (string) formated string
+     > Usage
+     | var x = 10,
+     |     y = 20,
+     |     width = 40,
+     |     height = 50;
+     | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+     | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width));
+     \*/
+    R.format = function (token, params) {
+        var args = R.is(params, array) ? [0][concat](params) : arguments;
+        token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) {
+            return args[++i] == null ? E : args[i];
+        }));
+        return token || E;
+    };
+    /*\
+     * Raphael.fullfill
+     [ method ]
+     **
+     * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{<name>}`” to the corresponding argument.
+     **
+     > Parameters
+     **
+     - token (string) string to format
+     - json (object) object which properties will be used as a replacement
+     = (string) formated string
+     > Usage
+     | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z"
+     | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
+     |     x: 10,
+     |     y: 20,
+     |     dim: {
+     |         width: 40,
+     |         height: 50,
+     |         "negative width": -40
+     |     }
+     | }));
+     \*/
+    R.fullfill = (function () {
+        var tokenRegex = /\{([^\}]+)\}/g,
+            objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
+            replacer = function (all, key, obj) {
+                var res = obj;
+                key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
+                    name = name || quotedName;
+                    if (res) {
+                        if (name in res) {
+                            res = res[name];
+                        }
+                        typeof res == "function" && isFunc && (res = res());
+                    }
+                });
+                res = (res == null || res == obj ? all : res) + "";
+                return res;
+            };
+        return function (str, obj) {
+            return String(str).replace(tokenRegex, function (all, key) {
+                return replacer(all, key, obj);
+            });
+        };
+    })();
+    /*\
+     * Raphael.ninja
+     [ method ]
+     **
+     * If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable `Raphael`, but anyway.) You can use `ninja` method.
+     * Beware, that in this case plugins could stop working, because they are depending on global variable existence.
+     **
+     = (object) Raphael object
+     > Usage
+     | (function (local_raphael) {
+     |     var paper = local_raphael(10, 10, 320, 200);
+     |     …
+     | })(Raphael.ninja());
+     \*/
+    R.ninja = function () {
+        oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
+        return R;
+    };
+    /*\
+     * Raphael.st
+     [ property (object) ]
+     **
+     * You can add your own method to elements and sets. It is wise to add a set method for each element method
+     * you added, so you will be able to call the same method on sets too.
+     **
+     * See also @Raphael.el.
+     > Usage
+     | Raphael.el.red = function () {
+     |     this.attr({fill: "#f00"});
+     | };
+     | Raphael.st.red = function () {
+     |     this.forEach(function (el) {
+     |         el.red();
+     |     });
+     | };
+     | // then use it
+     | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
+     \*/
+    R.st = setproto;
+
+    eve.on("raphael.DOMload", function () {
+        loaded = true;
+    });
+
+    // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+    (function (doc, loaded, f) {
+        if (doc.readyState == null && doc.addEventListener){
+            doc.addEventListener(loaded, f = function () {
+                doc.removeEventListener(loaded, f, false);
+                doc.readyState = "complete";
+            }, false);
+            doc.readyState = "loading";
+        }
+        function isLoaded() {
+            (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload");
+        }
+        isLoaded();
+    })(document, "DOMContentLoaded");
+
+    return R;
+}));
+
+// ┌─────────────────────────────────────────────────────────────────────┐ \\
+// │ Raphaël 2.1.4 - JavaScript Vector Library                       │ \\
+// ├─────────────────────────────────────────────────────────────────────┤ \\
+// │ SVG Module                                                          │ \\
+// ├─────────────────────────────────────────────────────────────────────┤ \\
+// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
+// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
+// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
+// └─────────────────────────────────────────────────────────────────────┘ \\
+
+(function (glob, factory) {
+    if (typeof define === "function" && define.amd) {
+        define("raphael.svg", ["raphael.core"], function(raphael) {
+            return factory(raphael);
+        });
+    } else if (typeof exports === "object") {
+        factory(require("raphael.core"));
+    } else {
+        factory(glob.Raphael);
+    }
+}(this, function(R) {
+    if (R && !R.svg) {
+        return;
+    }
+
+    var has = "hasOwnProperty",
+        Str = String,
+        toFloat = parseFloat,
+        toInt = parseInt,
+        math = Math,
+        mmax = math.max,
+        abs = math.abs,
+        pow = math.pow,
+        separator = /[, ]+/,
+        eve = R.eve,
+        E = "",
+        S = " ";
+    var xlink = "http://www.w3.org/1999/xlink",
+        markers = {
+            block: "M5,0 0,2.5 5,5z",
+            classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
+            diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
+            open: "M6,1 1,3.5 6,6",
+            oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
+        },
+        markerCounter = {};
+    R.toString = function () {
+        return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
+    };
+    var $ = function (el, attr) {
+            if (attr) {
+                if (typeof el == "string") {
+                    el = $(el);
+                }
+                for (var key in attr) if (attr[has](key)) {
+                    if (key.substring(0, 6) == "xlink:") {
+                        el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
+                    } else {
+                        el.setAttribute(key, Str(attr[key]));
+                    }
+                }
+            } else {
+                el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
+                el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
+            }
+            return el;
+        },
+        addGradientFill = function (element, gradient) {
+            var type = "linear",
+                id = element.id + gradient,
+                fx = .5, fy = .5,
+                o = element.node,
+                SVG = element.paper,
+                s = o.style,
+                el = R._g.doc.getElementById(id);
+            if (!el) {
+                gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
+                    type = "radial";
+                    if (_fx && _fy) {
+                        fx = toFloat(_fx);
+                        fy = toFloat(_fy);
+                        var dir = ((fy > .5) * 2 - 1);
+                        pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
+                        (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
+                        fy != .5 &&
+                        (fy = fy.toFixed(5) - 1e-5 * dir);
+                    }
+                    return E;
+                });
+                gradient = gradient.split(/\s*\-\s*/);
+                if (type == "linear") {
+                    var angle = gradient.shift();
+                    angle = -toFloat(angle);
+                    if (isNaN(angle)) {
+                        return null;
+                    }
+                    var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
+                        max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
+                    vector[2] *= max;
+                    vector[3] *= max;
+                    if (vector[2] < 0) {
+                        vector[0] = -vector[2];
+                        vector[2] = 0;
+                    }
+                    if (vector[3] < 0) {
+                        vector[1] = -vector[3];
+                        vector[3] = 0;
+                    }
+                }
+                var dots = R._parseDots(gradient);
+                if (!dots) {
+                    return null;
+                }
+                id = id.replace(/[\(\)\s,\xb0#]/g, "_");
+
+                if (element.gradient && id != element.gradient.id) {
+                    SVG.defs.removeChild(element.gradient);
+                    delete element.gradient;
+                }
+
+                if (!element.gradient) {
+                    el = $(type + "Gradient", {id: id});
+                    element.gradient = el;
+                    $(el, type == "radial" ? {
+                        fx: fx,
+                        fy: fy
+                    } : {
+                        x1: vector[0],
+                        y1: vector[1],
+                        x2: vector[2],
+                        y2: vector[3],
+                        gradientTransform: element.matrix.invert()
+                    });
+                    SVG.defs.appendChild(el);
+                    for (var i = 0, ii = dots.length; i < ii; i++) {
+                        el.appendChild($("stop", {
+                            offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
+                            "stop-color": dots[i].color || "#fff",
+                            "stop-opacity": isFinite(dots[i].opacity) ? dots[i].opacity : 1
+                        }));
+                    }
+                }
+            }
+            $(o, {
+                fill: "url('" + document.location.origin + document.location.pathname + "#" + id + "')",
+                opacity: 1,
+                "fill-opacity": 1
+            });
+            s.fill = E;
+            s.opacity = 1;
+            s.fillOpacity = 1;
+            return 1;
+        },
+        updatePosition = function (o) {
+            var bbox = o.getBBox(1);
+            $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
+        },
+        addArrow = function (o, value, isEnd) {
+            if (o.type == "path") {
+                var values = Str(value).toLowerCase().split("-"),
+                    p = o.paper,
+                    se = isEnd ? "end" : "start",
+                    node = o.node,
+                    attrs = o.attrs,
+                    stroke = attrs["stroke-width"],
+                    i = values.length,
+                    type = "classic",
+                    from,
+                    to,
+                    dx,
+                    refX,
+                    attr,
+                    w = 3,
+                    h = 3,
+                    t = 5;
+                while (i--) {
+                    switch (values[i]) {
+                        case "block":
+                        case "classic":
+                        case "oval":
+                        case "diamond":
+                        case "open":
+                        case "none":
+                            type = values[i];
+                            break;
+                        case "wide": h = 5; break;
+                        case "narrow": h = 2; break;
+                        case "long": w = 5; break;
+                        case "short": w = 2; break;
+                    }
+                }
+                if (type == "open") {
+                    w += 2;
+                    h += 2;
+                    t += 2;
+                    dx = 1;
+                    refX = isEnd ? 4 : 1;
+                    attr = {
+                        fill: "none",
+                        stroke: attrs.stroke
+                    };
+                } else {
+                    refX = dx = w / 2;
+                    attr = {
+                        fill: attrs.stroke,
+                        stroke: "none"
+                    };
+                }
+                if (o._.arrows) {
+                    if (isEnd) {
+                        o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
+                        o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
+                    } else {
+                        o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
+                        o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
+                    }
+                } else {
+                    o._.arrows = {};
+                }
+                if (type != "none") {
+                    var pathId = "raphael-marker-" + type,
+                        markerId = "raphael-marker-" + se + type + w + h + "-obj" + o.id;
+                    if (!R._g.doc.getElementById(pathId)) {
+                        p.defs.appendChild($($("path"), {
+                            "stroke-linecap": "round",
+                            d: markers[type],
+                            id: pathId
+                        }));
+                        markerCounter[pathId] = 1;
+                    } else {
+                        markerCounter[pathId]++;
+                    }
+                    var marker = R._g.doc.getElementById(markerId),
+                        use;
+                    if (!marker) {
+                        marker = $($("marker"), {
+                            id: markerId,
+                            markerHeight: h,
+                            markerWidth: w,
+                            orient: "auto",
+                            refX: refX,
+                            refY: h / 2
+                        });
+                        use = $($("use"), {
+                            "xlink:href": "#" + pathId,
+                            transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")",
+                            "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4)
+                        });
+                        marker.appendChild(use);
+                        p.defs.appendChild(marker);
+                        markerCounter[markerId] = 1;
+                    } else {
+                        markerCounter[markerId]++;
+                        use = marker.getElementsByTagName("use")[0];
+                    }
+                    $(use, attr);
+                    var delta = dx * (type != "diamond" && type != "oval");
+                    if (isEnd) {
+                        from = o._.arrows.startdx * stroke || 0;
+                        to = R.getTotalLength(attrs.path) - delta * stroke;
+                    } else {
+                        from = delta * stroke;
+                        to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+                    }
+                    attr = {};
+                    attr["marker-" + se] = "url(#" + markerId + ")";
+                    if (to || from) {
+                        attr.d = R.getSubpath(attrs.path, from, to);
+                    }
+                    $(node, attr);
+                    o._.arrows[se + "Path"] = pathId;
+                    o._.arrows[se + "Marker"] = markerId;
+                    o._.arrows[se + "dx"] = delta;
+                    o._.arrows[se + "Type"] = type;
+                    o._.arrows[se + "String"] = value;
+                } else {
+                    if (isEnd) {
+                        from = o._.arrows.startdx * stroke || 0;
+                        to = R.getTotalLength(attrs.path) - from;
+                    } else {
+                        from = 0;
+                        to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
+                    }
+                    o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)});
+                    delete o._.arrows[se + "Path"];
+                    delete o._.arrows[se + "Marker"];
+                    delete o._.arrows[se + "dx"];
+                    delete o._.arrows[se + "Type"];
+                    delete o._.arrows[se + "String"];
+                }
+                for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
+                    var item = R._g.doc.getElementById(attr);
+                    item && item.parentNode.removeChild(item);
+                }
+            }
+        },
+        dasharray = {
+            "-": [3, 1],
+            ".": [1, 1],
+            "-.": [3, 1, 1, 1],
+            "-..": [3, 1, 1, 1, 1, 1],
+            ". ": [1, 3],
+            "- ": [4, 3],
+            "--": [8, 3],
+            "- .": [4, 3, 1, 3],
+            "--.": [8, 3, 1, 3],
+            "--..": [8, 3, 1, 3, 1, 3]
+        },
+        addDashes = function (o, value, params) {
+            value = dasharray[Str(value).toLowerCase()];
+            if (value) {
+                var width = o.attrs["stroke-width"] || "1",
+                    butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
+                    dashes = [],
+                    i = value.length;
+                while (i--) {
+                    dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
+                }
+                $(o.node, {"stroke-dasharray": dashes.join(",")});
+            }
+            else {
+                $(o.node, {"stroke-dasharray": "none"});
+            }
+        },
+        setFillAndStroke = function (o, params) {
+            var node = o.node,
+                attrs = o.attrs,
+                vis = node.style.visibility;
+            node.style.visibility = "hidden";
+            for (var att in params) {
+                if (params[has](att)) {
+                    if (!R._availableAttrs[has](att)) {
+                        continue;
+                    }
+                    var value = params[att];
+                    attrs[att] = value;
+                    switch (att) {
+                        case "blur":
+                            o.blur(value);
+                            break;
+                        case "title":
+                            var title = node.getElementsByTagName("title");
+
+                            // Use the existing <title>.
+                            if (title.length && (title = title[0])) {
+                                title.firstChild.nodeValue = value;
+                            } else {
+                                title = $("title");
+                                var val = R._g.doc.createTextNode(value);
+                                title.appendChild(val);
+                                node.appendChild(title);
+                            }
+                            break;
+                        case "href":
+                        case "target":
+                            var pn = node.parentNode;
+                            if (pn.tagName.toLowerCase() != "a") {
+                                var hl = $("a");
+                                pn.insertBefore(hl, node);
+                                hl.appendChild(node);
+                                pn = hl;
+                            }
+                            if (att == "target") {
+                                pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value);
+                            } else {
+                                pn.setAttributeNS(xlink, att, value);
+                            }
+                            break;
+                        case "cursor":
+                            node.style.cursor = value;
+                            break;
+                        case "transform":
+                            o.transform(value);
+                            break;
+                        case "arrow-start":
+                            addArrow(o, value);
+                            break;
+                        case "arrow-end":
+                            addArrow(o, value, 1);
+                            break;
+                        case "clip-rect":
+                            var rect = Str(value).split(separator);
+                            if (rect.length == 4) {
+                                o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
+                                var el = $("clipPath"),
+                                    rc = $("rect");
+                                el.id = R.createUUID();
+                                $(rc, {
+                                    x: rect[0],
+                                    y: rect[1],
+                                    width: rect[2],
+                                    height: rect[3]
+                                });
+                                el.appendChild(rc);
+                                o.paper.defs.appendChild(el);
+                                $(node, {"clip-path": "url(#" + el.id + ")"});
+                                o.clip = rc;
+                            }
+                            if (!value) {
+                                var path = node.getAttribute("clip-path");
+                                if (path) {
+                                    var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
+                                    clip && clip.parentNode.removeChild(clip);
+                                    $(node, {"clip-path": E});
+                                    delete o.clip;
+                                }
+                            }
+                            break;
+                        case "path":
+                            if (o.type == "path") {
+                                $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
+                                o._.dirty = 1;
+                                if (o._.arrows) {
+                                    "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+                                    "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+                                }
+                            }
+                            break;
+                        case "width":
+                            node.setAttribute(att, value);
+                            o._.dirty = 1;
+                            if (attrs.fx) {
+                                att = "x";
+                                value = attrs.x;
+                            } else {
+                                break;
+                            }
+                        case "x":
+                            if (attrs.fx) {
+                                value = -attrs.x - (attrs.width || 0);
+                            }
+                        case "rx":
+                            if (att == "rx" && o.type == "rect") {
+                                break;
+                            }
+                        case "cx":
+                            node.setAttribute(att, value);
+                            o.pattern && updatePosition(o);
+                            o._.dirty = 1;
+                            break;
+                        case "height":
+                            node.setAttribute(att, value);
+                            o._.dirty = 1;
+                            if (attrs.fy) {
+                                att = "y";
+                                value = attrs.y;
+                            } else {
+                                break;
+                            }
+                        case "y":
+                            if (attrs.fy) {
+                                value = -attrs.y - (attrs.height || 0);
+                            }
+                        case "ry":
+                            if (att == "ry" && o.type == "rect") {
+                                break;
+                            }
+                        case "cy":
+                            node.setAttribute(att, value);
+                            o.pattern && updatePosition(o);
+                            o._.dirty = 1;
+                            break;
+                        case "r":
+                            if (o.type == "rect") {
+                                $(node, {rx: value, ry: value});
+                            } else {
+                                node.setAttribute(att, value);
+                            }
+                            o._.dirty = 1;
+                            break;
+                        case "src":
+                            if (o.type == "image") {
+                                node.setAttributeNS(xlink, "href", value);
+                            }
+                            break;
+                        case "stroke-width":
+                            if (o._.sx != 1 || o._.sy != 1) {
+                                value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
+                            }
+                            node.setAttribute(att, value);
+                            if (attrs["stroke-dasharray"]) {
+                                addDashes(o, attrs["stroke-dasharray"], params);
+                            }
+                            if (o._.arrows) {
+                                "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+                                "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+                            }
+                            break;
+                        case "stroke-dasharray":
+                            addDashes(o, value, params);
+                            break;
+                        case "fill":
+                            var isURL = Str(value).match(R._ISURL);
+                            if (isURL) {
+                                el = $("pattern");
+                                var ig = $("image");
+                                el.id = R.createUUID();
+                                $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
+                                $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
+                                el.appendChild(ig);
+
+                                (function (el) {
+                                    R._preload(isURL[1], function () {
+                                        var w = this.offsetWidth,
+                                            h = this.offsetHeight;
+                                        $(el, {width: w, height: h});
+                                        $(ig, {width: w, height: h});
+                                    });
+                                })(el);
+                                o.paper.defs.appendChild(el);
+                                $(node, {fill: "url(#" + el.id + ")"});
+                                o.pattern = el;
+                                o.pattern && updatePosition(o);
+                                break;
+                            }
+                            var clr = R.getRGB(value);
+                            if (!clr.error) {
+                                delete params.gradient;
+                                delete attrs.gradient;
+                                !R.is(attrs.opacity, "undefined") &&
+                                R.is(params.opacity, "undefined") &&
+                                $(node, {opacity: attrs.opacity});
+                                !R.is(attrs["fill-opacity"], "undefined") &&
+                                R.is(params["fill-opacity"], "undefined") &&
+                                $(node, {"fill-opacity": attrs["fill-opacity"]});
+                            } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
+                                if ("opacity" in attrs || "fill-opacity" in attrs) {
+                                    var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+                                    if (gradient) {
+                                        var stops = gradient.getElementsByTagName("stop");
+                                        $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
+                                    }
+                                }
+                                attrs.gradient = value;
+                                attrs.fill = "none";
+                                break;
+                            }
+                            clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
+                        case "stroke":
+                            clr = R.getRGB(value);
+                            node.setAttribute(att, clr.hex);
+                            att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
+                            if (att == "stroke" && o._.arrows) {
+                                "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
+                                "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
+                            }
+                            break;
+                        case "gradient":
+                            (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
+                            break;
+                        case "opacity":
+                            if (attrs.gradient && !attrs[has]("stroke-opacity")) {
+                                $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
+                            }
+                        // fall
+                        case "fill-opacity":
+                            if (attrs.gradient) {
+                                gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+                                if (gradient) {
+                                    stops = gradient.getElementsByTagName("stop");
+                                    $(stops[stops.length - 1], {"stop-opacity": value});
+                                }
+                                break;
+                            }
+                        default:
+                            att == "font-size" && (value = toInt(value, 10) + "px");
+                            var cssrule = att.replace(/(\-.)/g, function (w) {
+                                return w.substring(1).toUpperCase();
+                            });
+                            node.style[cssrule] = value;
+                            o._.dirty = 1;
+                            node.setAttribute(att, value);
+                            break;
+                    }
+                }
+            }
+
+            tuneText(o, params);
+            node.style.visibility = vis;
+        },
+        leading = 1.2,
+        tuneText = function (el, params) {
+            if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
+                return;
+            }
+            var a = el.attrs,
+                node = el.node,
+                fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
+
+            if (params[has]("text")) {
+                a.text = params.text;
+                while (node.firstChild) {
+                    node.removeChild(node.firstChild);
+                }
+                var texts = Str(params.text).split("\n"),
+                    tspans = [],
+                    tspan;
+                for (var i = 0, ii = texts.length; i < ii; i++) {
+                    tspan = $("tspan");
+                    i && $(tspan, {dy: fontSize * leading, x: a.x});
+                    tspan.appendChild(R._g.doc.createTextNode(texts[i]));
+                    node.appendChild(tspan);
+                    tspans[i] = tspan;
+                }
+            } else {
+                tspans = node.getElementsByTagName("tspan");
+                for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
+                    $(tspans[i], {dy: fontSize * leading, x: a.x});
+                } else {
+                    $(tspans[0], {dy: 0});
+                }
+            }
+            $(node, {x: a.x, y: a.y});
+            el._.dirty = 1;
+            var bb = el._getBBox(),
+                dif = a.y - (bb.y + bb.height / 2);
+            dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
+        },
+        getRealNode = function (node) {
+            if (node.parentNode && node.parentNode.tagName.toLowerCase() === "a") {
+                return node.parentNode;
+            } else {
+                return node;
+            }
+        },
+        Element = function (node, svg) {
+            var X = 0,
+                Y = 0;
+            /*\
+             * Element.node
+             [ property (object) ]
+             **
+             * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
+             **
+             * Note: Don’t mess with it.
+             > Usage
+             | // draw a circle at coordinate 10,10 with radius of 10
+             | var c = paper.circle(10, 10, 10);
+             | c.node.onclick = function () {
+             |     c.attr("fill", "red");
+             | };
+             \*/
+            this[0] = this.node = node;
+            /*\
+             * Element.raphael
+             [ property (object) ]
+             **
+             * Internal reference to @Raphael object. In case it is not available.
+             > Usage
+             | Raphael.el.red = function () {
+             |     var hsb = this.paper.raphael.rgb2hsb(this.attr("fill"));
+             |     hsb.h = 1;
+             |     this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex});
+             | }
+             \*/
+            node.raphael = true;
+            /*\
+             * Element.id
+             [ property (number) ]
+             **
+             * Unique id of the element. Especially useful when you want to listen to events of the element,
+             * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method.
+             \*/
+            this.id = R._oid++;
+            node.raphaelid = this.id;
+            this.matrix = R.matrix();
+            this.realPath = null;
+            /*\
+             * Element.paper
+             [ property (object) ]
+             **
+             * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions.
+             > Usage
+             | Raphael.el.cross = function () {
+             |     this.attr({fill: "red"});
+             |     this.paper.path("M10,10L50,50M50,10L10,50")
+             |         .attr({stroke: "red"});
+             | }
+             \*/
+            this.paper = svg;
+            this.attrs = this.attrs || {};
+            this._ = {
+                transform: [],
+                sx: 1,
+                sy: 1,
+                deg: 0,
+                dx: 0,
+                dy: 0,
+                dirty: 1
+            };
+            !svg.bottom && (svg.bottom = this);
+            /*\
+             * Element.prev
+             [ property (object) ]
+             **
+             * Reference to the previous element in the hierarchy.
+             \*/
+            this.prev = svg.top;
+            svg.top && (svg.top.next = this);
+            svg.top = this;
+            /*\
+             * Element.next
+             [ property (object) ]
+             **
+             * Reference to the next element in the hierarchy.
+             \*/
+            this.next = null;
+        },
+        elproto = R.el;
+
+    Element.prototype = elproto;
+    elproto.constructor = Element;
+
+    R._engine.path = function (pathString, SVG) {
+        var el = $("path");
+        SVG.canvas && SVG.canvas.appendChild(el);
+        var p = new Element(el, SVG);
+        p.type = "path";
+        setFillAndStroke(p, {
+            fill: "none",
+            stroke: "#000",
+            path: pathString
+        });
+        return p;
+    };
+    /*\
+     * Element.rotate
+     [ method ]
+     **
+     * Deprecated! Use @Element.transform instead.
+     * Adds rotation by given angle around given point to the list of
+     * transformations of the element.
+     > Parameters
+     - deg (number) angle in degrees
+     - cx (number) #optional x coordinate of the centre of rotation
+     - cy (number) #optional y coordinate of the centre of rotation
+     * If cx & cy aren’t specified centre of the shape is used as a point of rotation.
+     = (object) @Element
+     \*/
+    elproto.rotate = function (deg, cx, cy) {
+        if (this.removed) {
+            return this;
+        }
+        deg = Str(deg).split(separator);
+        if (deg.length - 1) {
+            cx = toFloat(deg[1]);
+            cy = toFloat(deg[2]);
+        }
+        deg = toFloat(deg[0]);
+        (cy == null) && (cx = cy);
+        if (cx == null || cy == null) {
+            var bbox = this.getBBox(1);
+            cx = bbox.x + bbox.width / 2;
+            cy = bbox.y + bbox.height / 2;
+        }
+        this.transform(this._.transform.concat([["r", deg, cx, cy]]));
+        return this;
+    };
+    /*\
+     * Element.scale
+     [ method ]
+     **
+     * Deprecated! Use @Element.transform instead.
+     * Adds scale by given amount relative to given point to the list of
+     * transformations of the element.
+     > Parameters
+     - sx (number) horisontal scale amount
+     - sy (number) vertical scale amount
+     - cx (number) #optional x coordinate of the centre of scale
+     - cy (number) #optional y coordinate of the centre of scale
+     * If cx & cy aren’t specified centre of the shape is used instead.
+     = (object) @Element
+     \*/
+    elproto.scale = function (sx, sy, cx, cy) {
+        if (this.removed) {
+            return this;
+        }
+        sx = Str(sx).split(separator);
+        if (sx.length - 1) {
+            sy = toFloat(sx[1]);
+            cx = toFloat(sx[2]);
+            cy = toFloat(sx[3]);
+        }
+        sx = toFloat(sx[0]);
+        (sy == null) && (sy = sx);
+        (cy == null) && (cx = cy);
+        if (cx == null || cy == null) {
+            var bbox = this.getBBox(1);
+        }
+        cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+        cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+        this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
+        return this;
+    };
+    /*\
+     * Element.translate
+     [ method ]
+     **
+     * Deprecated! Use @Element.transform instead.
+     * Adds translation by given amount to the list of transformations of the element.
+     > Parameters
+     - dx (number) horisontal shift
+     - dy (number) vertical shift
+     = (object) @Element
+     \*/
+    elproto.translate = function (dx, dy) {
+        if (this.removed) {
+            return this;
+        }
+        dx = Str(dx).split(separator);
+        if (dx.length - 1) {
+            dy = toFloat(dx[1]);
+        }
+        dx = toFloat(dx[0]) || 0;
+        dy = +dy || 0;
+        this.transform(this._.transform.concat([["t", dx, dy]]));
+        return this;
+    };
+    /*\
+     * Element.transform
+     [ method ]
+     **
+     * Adds transformation to the element which is separate to other attributes,
+     * i.e. translation doesn’t change `x` or `y` of the rectange. The format
+     * of transformation string is similar to the path string syntax:
+     | "t100,100r30,100,100s2,2,100,100r45s1.5"
+     * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for
+     * scale and `m` is for matrix.
+     *
+     * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`.
+     *
+     * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100;
+     * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin
+     * coordinates as optional parameters, the default is the centre point of the element.
+     * Matrix accepts six parameters.
+     > Usage
+     | var el = paper.rect(10, 20, 300, 200);
+     | // translate 100, 100, rotate 45°, translate -100, 0
+     | el.transform("t100,100r45t-100,0");
+     | // if you want you can append or prepend transformations
+     | el.transform("...t50,50");
+     | el.transform("s2...");
+     | // or even wrap
+     | el.transform("t50,50...t-50-50");
+     | // to reset transformation call method with empty string
+     | el.transform("");
+     | // to get current value call it without parameters
+     | console.log(el.transform());
+     > Parameters
+     - tstr (string) #optional transformation string
+     * If tstr isn’t specified
+     = (string) current transformation string
+     * else
+     = (object) @Element
+     \*/
+    elproto.transform = function (tstr) {
+        var _ = this._;
+        if (tstr == null) {
+            return _.transform;
+        }
+        R._extractTransform(this, tstr);
+
+        this.clip && $(this.clip, {transform: this.matrix.invert()});
+        this.pattern && updatePosition(this);
+        this.node && $(this.node, {transform: this.matrix});
+
+        if (_.sx != 1 || _.sy != 1) {
+            var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
+            this.attr({"stroke-width": sw});
+        }
+
+        return this;
+    };
+    /*\
+     * Element.hide
+     [ method ]
+     **
+     * Makes element invisible. See @Element.show.
+     = (object) @Element
+     \*/
+    elproto.hide = function () {
+        if(!this.removed) this.node.style.display = "none";
+        return this;
+    };
+    /*\
+     * Element.show
+     [ method ]
+     **
+     * Makes element visible. See @Element.hide.
+     = (object) @Element
+     \*/
+    elproto.show = function () {
+        if(!this.removed) this.node.style.display = "";
+        return this;
+    };
+    /*\
+     * Element.remove
+     [ method ]
+     **
+     * Removes element from the paper.
+     \*/
+    elproto.remove = function () {
+        var node = getRealNode(this.node);
+        if (this.removed || !node.parentNode) {
+            return;
+        }
+        var paper = this.paper;
+        paper.__set__ && paper.__set__.exclude(this);
+        eve.unbind("raphael.*.*." + this.id);
+        if (this.gradient) {
+            paper.defs.removeChild(this.gradient);
+        }
+        R._tear(this, paper);
+
+        node.parentNode.removeChild(node);
+
+        // Remove custom data for element
+        this.removeData();
+
+        for (var i in this) {
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+        }
+        this.removed = true;
+    };
+    elproto._getBBox = function () {
+        if (this.node.style.display == "none") {
+            this.show();
+            var hide = true;
+        }
+        var canvasHidden = false,
+            containerStyle;
+        if (this.paper.canvas.parentElement) {
+            containerStyle = this.paper.canvas.parentElement.style;
+        } //IE10+ can't find parentElement
+        else if (this.paper.canvas.parentNode) {
+            containerStyle = this.paper.canvas.parentNode.style;
+        }
+
+        if(containerStyle && containerStyle.display == "none") {
+            canvasHidden = true;
+            containerStyle.display = "";
+        }
+        var bbox = {};
+        try {
+            bbox = this.node.getBBox();
+        } catch(e) {
+            // Firefox 3.0.x, 25.0.1 (probably more versions affected) play badly here - possible fix
+            bbox = {
+                x: this.node.clientLeft,
+                y: this.node.clientTop,
+                width: this.node.clientWidth,
+                height: this.node.clientHeight
+            }
+        } finally {
+            bbox = bbox || {};
+            if(canvasHidden){
+                containerStyle.display = "none";
+            }
+        }
+        hide && this.hide();
+        return bbox;
+    };
+    /*\
+     * Element.attr
+     [ method ]
+     **
+     * Sets the attributes of the element.
+     > Parameters
+     - attrName (string) attribute’s name
+     - value (string) value
+     * or
+     - params (object) object of name/value pairs
+     * or
+     - attrName (string) attribute’s name
+     * or
+     - attrNames (array) in this case method returns array of current values for given attribute names
+     = (object) @Element if attrsName & value or params are passed in.
+     = (...) value of the attribute if only attrsName is passed in.
+     = (array) array of values of the attribute if attrsNames is passed in.
+     = (object) object of attributes if nothing is passed in.
+     > Possible parameters
+     # <p>Please refer to the <a href="http://www.w3.org/TR/SVG/" title="The W3C Recommendation for the SVG language describes these properties in detail.">SVG specification</a> for an explanation of these parameters.</p>
+     o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `medium`, length: `long`, `short`, `midium`.
+     o clip-rect (string) comma or space separated values: x, y, width and height
+     o cursor (string) CSS type of the cursor
+     o cx (number) the x-axis coordinate of the center of the circle, or ellipse
+     o cy (number) the y-axis coordinate of the center of the circle, or ellipse
+     o fill (string) colour, gradient or image
+     o fill-opacity (number)
+     o font (string)
+     o font-family (string)
+     o font-size (number) font size in pixels
+     o font-weight (string)
+     o height (number)
+     o href (string) URL, if specified element behaves as hyperlink
+     o opacity (number)
+     o path (string) SVG path string format
+     o r (number) radius of the circle, ellipse or rounded corner on the rect
+     o rx (number) horisontal radius of the ellipse
+     o ry (number) vertical radius of the ellipse
+     o src (string) image URL, only works for @Element.image element
+     o stroke (string) stroke colour
+     o stroke-dasharray (string) [“”, “none”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”]
+     o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”]
+     o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”]
+     o stroke-miterlimit (number)
+     o stroke-opacity (number)
+     o stroke-width (number) stroke width in pixels, default is '1'
+     o target (string) used with href
+     o text (string) contents of the text element. Use `\n` for multiline text
+     o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`”
+     o title (string) will create tooltip with a given text
+     o transform (string) see @Element.transform
+     o width (number)
+     o x (number)
+     o y (number)
+     > Gradients
+     * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90°
+     * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black.
+     *
+     * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” –
+     * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point
+     * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses.
+     > Path String
+     # <p>Please refer to <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path’s data attribute’s format are described in the SVG specification.">SVG documentation regarding path string</a>. Raphaël fully supports it.</p>
+     > Colour Parsing
+     # <ul>
+     #     <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li>
+     #     <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li>
+     #     <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li>
+     #     <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200,&nbsp;100,&nbsp;0)</code>”)</li>
+     #     <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%,&nbsp;175%,&nbsp;0%)</code>”)</li>
+     #     <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200,&nbsp;100,&nbsp;0, .5)</code>”)</li>
+     #     <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%,&nbsp;175%,&nbsp;0%, 50%)</code>”)</li>
+     #     <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5,&nbsp;0.25,&nbsp;1)</code>”)</li>
+     #     <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
+     #     <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li>
+     #     <li>hsl(•••, •••, •••) — almost the same as hsb, see <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" title="HSL and HSV - Wikipedia, the free encyclopedia">Wikipedia page</a></li>
+     #     <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
+     #     <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li>
+     #     <li>Optionally for hsb and hsl you could specify hue as a degree: “<code>hsl(240deg,&nbsp;1,&nbsp;.5)</code>” or, if you want to go fancy, “<code>hsl(240°,&nbsp;1,&nbsp;.5)</code>”</li>
+     # </ul>
+     \*/
+    elproto.attr = function (name, value) {
+        if (this.removed) {
+            return this;
+        }
+        if (name == null) {
+            var res = {};
+            for (var a in this.attrs) if (this.attrs[has](a)) {
+                res[a] = this.attrs[a];
+            }
+            res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+            res.transform = this._.transform;
+            return res;
+        }
+        if (value == null && R.is(name, "string")) {
+            if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
+                return this.attrs.gradient;
+            }
+            if (name == "transform") {
+                return this._.transform;
+            }
+            var names = name.split(separator),
+                out = {};
+            for (var i = 0, ii = names.length; i < ii; i++) {
+                name = names[i];
+                if (name in this.attrs) {
+                    out[name] = this.attrs[name];
+                } else if (R.is(this.paper.customAttributes[name], "function")) {
+                    out[name] = this.paper.customAttributes[name].def;
+                } else {
+                    out[name] = R._availableAttrs[name];
+                }
+            }
+            return ii - 1 ? out : out[names[0]];
+        }
+        if (value == null && R.is(name, "array")) {
+            out = {};
+            for (i = 0, ii = name.length; i < ii; i++) {
+                out[name[i]] = this.attr(name[i]);
+            }
+            return out;
+        }
+        if (value != null) {
+            var params = {};
+            params[name] = value;
+        } else if (name != null && R.is(name, "object")) {
+            params = name;
+        }
+        for (var key in params) {
+            eve("raphael.attr." + key + "." + this.id, this, params[key]);
+        }
+        for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
+            var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
+            this.attrs[key] = params[key];
+            for (var subkey in par) if (par[has](subkey)) {
+                params[subkey] = par[subkey];
+            }
+        }
+        setFillAndStroke(this, params);
+        return this;
+    };
+    /*\
+     * Element.toFront
+     [ method ]
+     **
+     * Moves the element so it is the closest to the viewer’s eyes, on top of other elements.
+     = (object) @Element
+     \*/
+    elproto.toFront = function () {
+        if (this.removed) {
+            return this;
+        }
+        var node = getRealNode(this.node);
+        node.parentNode.appendChild(node);
+        var svg = this.paper;
+        svg.top != this && R._tofront(this, svg);
+        return this;
+    };
+    /*\
+     * Element.toBack
+     [ method ]
+     **
+     * Moves the element so it is the furthest from the viewer’s eyes, behind other elements.
+     = (object) @Element
+     \*/
+    elproto.toBack = function () {
+        if (this.removed) {
+            return this;
+        }
+        var node = getRealNode(this.node);
+        var parentNode = node.parentNode;
+        parentNode.insertBefore(node, parentNode.firstChild);
+        R._toback(this, this.paper);
+        var svg = this.paper;
+        return this;
+    };
+    /*\
+     * Element.insertAfter
+     [ method ]
+     **
+     * Inserts current object after the given one.
+     = (object) @Element
+     \*/
+    elproto.insertAfter = function (element) {
+        if (this.removed || !element) {
+            return this;
+        }
+
+        var node = getRealNode(this.node);
+        var afterNode = getRealNode(element.node || element[element.length - 1].node);
+        if (afterNode.nextSibling) {
+            afterNode.parentNode.insertBefore(node, afterNode.nextSibling);
+        } else {
+            afterNode.parentNode.appendChild(node);
+        }
+        R._insertafter(this, element, this.paper);
+        return this;
+    };
+    /*\
+     * Element.insertBefore
+     [ method ]
+     **
+     * Inserts current object before the given one.
+     = (object) @Element
+     \*/
+    elproto.insertBefore = function (element) {
+        if (this.removed || !element) {
+            return this;
+        }
+
+        var node = getRealNode(this.node);
+        var beforeNode = getRealNode(element.node || element[0].node);
+        beforeNode.parentNode.insertBefore(node, beforeNode);
+        R._insertbefore(this, element, this.paper);
+        return this;
+    };
+    elproto.blur = function (size) {
+        // Experimental. No Safari support. Use it on your own risk.
+        var t = this;
+        if (+size !== 0) {
+            var fltr = $("filter"),
+                blur = $("feGaussianBlur");
+            t.attrs.blur = size;
+            fltr.id = R.createUUID();
+            $(blur, {stdDeviation: +size || 1.5});
+            fltr.appendChild(blur);
+            t.paper.defs.appendChild(fltr);
+            t._blur = fltr;
+            $(t.node, {filter: "url(#" + fltr.id + ")"});
+        } else {
+            if (t._blur) {
+                t._blur.parentNode.removeChild(t._blur);
+                delete t._blur;
+                delete t.attrs.blur;
+            }
+            t.node.removeAttribute("filter");
+        }
+        return t;
+    };
+    R._engine.circle = function (svg, x, y, r) {
+        var el = $("circle");
+        svg.canvas && svg.canvas.appendChild(el);
+        var res = new Element(el, svg);
+        res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
+        res.type = "circle";
+        $(el, res.attrs);
+        return res;
+    };
+    R._engine.rect = function (svg, x, y, w, h, r) {
+        var el = $("rect");
+        svg.canvas && svg.canvas.appendChild(el);
+        var res = new Element(el, svg);
+        res.attrs = {x: x, y: y, width: w, height: h, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
+        res.type = "rect";
+        $(el, res.attrs);
+        return res;
+    };
+    R._engine.ellipse = function (svg, x, y, rx, ry) {
+        var el = $("ellipse");
+        svg.canvas && svg.canvas.appendChild(el);
+        var res = new Element(el, svg);
+        res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
+        res.type = "ellipse";
+        $(el, res.attrs);
+        return res;
+    };
+    R._engine.image = function (svg, src, x, y, w, h) {
+        var el = $("image");
+        $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
+        el.setAttributeNS(xlink, "href", src);
+        svg.canvas && svg.canvas.appendChild(el);
+        var res = new Element(el, svg);
+        res.attrs = {x: x, y: y, width: w, height: h, src: src};
+        res.type = "image";
+        return res;
+    };
+    R._engine.text = function (svg, x, y, text) {
+        var el = $("text");
+        svg.canvas && svg.canvas.appendChild(el);
+        var res = new Element(el, svg);
+        res.attrs = {
+            x: x,
+            y: y,
+            "text-anchor": "middle",
+            text: text,
+            "font-family": R._availableAttrs["font-family"],
+            "font-size": R._availableAttrs["font-size"],
+            stroke: "none",
+            fill: "#000"
+        };
+        res.type = "text";
+        setFillAndStroke(res, res.attrs);
+        return res;
+    };
+    R._engine.setSize = function (width, height) {
+        this.width = width || this.width;
+        this.height = height || this.height;
+        this.canvas.setAttribute("width", this.width);
+        this.canvas.setAttribute("height", this.height);
+        if (this._viewBox) {
+            this.setViewBox.apply(this, this._viewBox);
+        }
+        return this;
+    };
+    R._engine.create = function () {
+        var con = R._getContainer.apply(0, arguments),
+            container = con && con.container,
+            x = con.x,
+            y = con.y,
+            width = con.width,
+            height = con.height;
+        if (!container) {
+            throw new Error("SVG container not found.");
+        }
+        var cnvs = $("svg"),
+            css = "overflow:hidden;",
+            isFloating;
+        x = x || 0;
+        y = y || 0;
+        width = width || 512;
+        height = height || 342;
+        $(cnvs, {
+            height: height,
+            version: 1.1,
+            width: width,
+            xmlns: "http://www.w3.org/2000/svg",
+            "xmlns:xlink": "http://www.w3.org/1999/xlink"
+        });
+        if (container == 1) {
+            cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
+            R._g.doc.body.appendChild(cnvs);
+            isFloating = 1;
+        } else {
+            cnvs.style.cssText = css + "position:relative";
+            if (container.firstChild) {
+                container.insertBefore(cnvs, container.firstChild);
+            } else {
+                container.appendChild(cnvs);
+            }
+        }
+        container = new R._Paper;
+        container.width = width;
+        container.height = height;
+        container.canvas = cnvs;
+        container.clear();
+        container._left = container._top = 0;
+        isFloating && (container.renderfix = function () {});
+        container.renderfix();
+        return container;
+    };
+    R._engine.setViewBox = function (x, y, w, h, fit) {
+        eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+        var paperSize = this.getSize(),
+            size = mmax(w / paperSize.width, h / paperSize.height),
+            top = this.top,
+            aspectRatio = fit ? "xMidYMid meet" : "xMinYMin",
+            vb,
+            sw;
+        if (x == null) {
+            if (this._vbSize) {
+                size = 1;
+            }
+            delete this._vbSize;
+            vb = "0 0 " + this.width + S + this.height;
+        } else {
+            this._vbSize = size;
+            vb = x + S + y + S + w + S + h;
+        }
+        $(this.canvas, {
+            viewBox: vb,
+            preserveAspectRatio: aspectRatio
+        });
+        while (size && top) {
+            sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
+            top.attr({"stroke-width": sw});
+            top._.dirty = 1;
+            top._.dirtyT = 1;
+            top = top.prev;
+        }
+        this._viewBox = [x, y, w, h, !!fit];
+        return this;
+    };
+    /*\
+     * Paper.renderfix
+     [ method ]
+     **
+     * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant
+     * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness.
+     * This method fixes the issue.
+     **
+     Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method.
+     \*/
+    R.prototype.renderfix = function () {
+        var cnvs = this.canvas,
+            s = cnvs.style,
+            pos;
+        try {
+            pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix();
+        } catch (e) {
+            pos = cnvs.createSVGMatrix();
+        }
+        var left = -pos.e % 1,
+            top = -pos.f % 1;
+        if (left || top) {
+            if (left) {
+                this._left = (this._left + left) % 1;
+                s.left = this._left + "px";
+            }
+            if (top) {
+                this._top = (this._top + top) % 1;
+                s.top = this._top + "px";
+            }
+        }
+    };
+    /*\
+     * Paper.clear
+     [ method ]
+     **
+     * Clears the paper, i.e. removes all the elements.
+     \*/
+    R.prototype.clear = function () {
+        R.eve("raphael.clear", this);
+        var c = this.canvas;
+        while (c.firstChild) {
+            c.removeChild(c.firstChild);
+        }
+        this.bottom = this.top = null;
+        (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
+        c.appendChild(this.desc);
+        c.appendChild(this.defs = $("defs"));
+    };
+    /*\
+     * Paper.remove
+     [ method ]
+     **
+     * Removes the paper from the DOM.
+     \*/
+    R.prototype.remove = function () {
+        eve("raphael.remove", this);
+        this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
+        for (var i in this) {
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+        }
+    };
+    var setproto = R.st;
+    for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
+        setproto[method] = (function (methodname) {
+            return function () {
+                var arg = arguments;
+                return this.forEach(function (el) {
+                    el[methodname].apply(el, arg);
+                });
+            };
+        })(method);
+    }
+}));
+
+// ┌─────────────────────────────────────────────────────────────────────┐ \\
+// │ Raphaël 2.1.4 - JavaScript Vector Library                       │ \\
+// ├─────────────────────────────────────────────────────────────────────┤ \\
+// │ VML Module                                                          │ \\
+// ├─────────────────────────────────────────────────────────────────────┤ \\
+// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
+// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
+// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
+// └─────────────────────────────────────────────────────────────────────┘ \\
+
+(function (glob, factory) {
+    if (typeof define === "function" && define.amd) {
+        define("raphael.vml", ["raphael.core"], function(raphael) {
+            return factory(raphael);
+        });
+    } else if (typeof exports === "object") {
+        factory(require("raphael"));
+    } else {
+        factory(glob.Raphael);
+    }
+}(this, function(R) {
+    if (R && !R.vml) {
+        return;
+    }
+
+    var has = "hasOwnProperty",
+        Str = String,
+        toFloat = parseFloat,
+        math = Math,
+        round = math.round,
+        mmax = math.max,
+        mmin = math.min,
+        abs = math.abs,
+        fillString = "fill",
+        separator = /[, ]+/,
+        eve = R.eve,
+        ms = " progid:DXImageTransform.Microsoft",
+        S = " ",
+        E = "",
+        map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
+        bites = /([clmz]),?([^clmz]*)/gi,
+        blurregexp = / progid:\S+Blur\([^\)]+\)/g,
+        val = /-?[^,\s-]+/g,
+        cssDot = "position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)",
+        zoom = 21600,
+        pathTypes = {path: 1, rect: 1, image: 1},
+        ovalTypes = {circle: 1, ellipse: 1},
+        path2vml = function (path) {
+            var total =  /[ahqstv]/ig,
+                command = R._pathToAbsolute;
+            Str(path).match(total) && (command = R._path2curve);
+            total = /[clmz]/g;
+            if (command == R._pathToAbsolute && !Str(path).match(total)) {
+                var res = Str(path).replace(bites, function (all, command, args) {
+                    var vals = [],
+                        isMove = command.toLowerCase() == "m",
+                        res = map[command];
+                    args.replace(val, function (value) {
+                        if (isMove && vals.length == 2) {
+                            res += vals + map[command == "m" ? "l" : "L"];
+                            vals = [];
+                        }
+                        vals.push(round(value * zoom));
+                    });
+                    return res + vals;
+                });
+                return res;
+            }
+            var pa = command(path), p, r;
+            res = [];
+            for (var i = 0, ii = pa.length; i < ii; i++) {
+                p = pa[i];
+                r = pa[i][0].toLowerCase();
+                r == "z" && (r = "x");
+                for (var j = 1, jj = p.length; j < jj; j++) {
+                    r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
+                }
+                res.push(r);
+            }
+            return res.join(S);
+        },
+        compensation = function (deg, dx, dy) {
+            var m = R.matrix();
+            m.rotate(-deg, .5, .5);
+            return {
+                dx: m.x(dx, dy),
+                dy: m.y(dx, dy)
+            };
+        },
+        setCoords = function (p, sx, sy, dx, dy, deg) {
+            var _ = p._,
+                m = p.matrix,
+                fillpos = _.fillpos,
+                o = p.node,
+                s = o.style,
+                y = 1,
+                flip = "",
+                dxdy,
+                kx = zoom / sx,
+                ky = zoom / sy;
+            s.visibility = "hidden";
+            if (!sx || !sy) {
+                return;
+            }
+            o.coordsize = abs(kx) + S + abs(ky);
+            s.rotation = deg * (sx * sy < 0 ? -1 : 1);
+            if (deg) {
+                var c = compensation(deg, dx, dy);
+                dx = c.dx;
+                dy = c.dy;
+            }
+            sx < 0 && (flip += "x");
+            sy < 0 && (flip += " y") && (y = -1);
+            s.flip = flip;
+            o.coordorigin = (dx * -kx) + S + (dy * -ky);
+            if (fillpos || _.fillsize) {
+                var fill = o.getElementsByTagName(fillString);
+                fill = fill && fill[0];
+                o.removeChild(fill);
+                if (fillpos) {
+                    c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
+                    fill.position = c.dx * y + S + c.dy * y;
+                }
+                if (_.fillsize) {
+                    fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
+                }
+                o.appendChild(fill);
+            }
+            s.visibility = "visible";
+        };
+    R.toString = function () {
+        return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
+    };
+    var addArrow = function (o, value, isEnd) {
+            var values = Str(value).toLowerCase().split("-"),
+                se = isEnd ? "end" : "start",
+                i = values.length,
+                type = "classic",
+                w = "medium",
+                h = "medium";
+            while (i--) {
+                switch (values[i]) {
+                    case "block":
+                    case "classic":
+                    case "oval":
+                    case "diamond":
+                    case "open":
+                    case "none":
+                        type = values[i];
+                        break;
+                    case "wide":
+                    case "narrow": h = values[i]; break;
+                    case "long":
+                    case "short": w = values[i]; break;
+                }
+            }
+            var stroke = o.node.getElementsByTagName("stroke")[0];
+            stroke[se + "arrow"] = type;
+            stroke[se + "arrowlength"] = w;
+            stroke[se + "arrowwidth"] = h;
+        },
+        setFillAndStroke = function (o, params) {
+            // o.paper.canvas.style.display = "none";
+            o.attrs = o.attrs || {};
+            var node = o.node,
+                a = o.attrs,
+                s = node.style,
+                xy,
+                newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r),
+                isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
+                res = o;
+
+
+            for (var par in params) if (params[has](par)) {
+                a[par] = params[par];
+            }
+            if (newpath) {
+                a.path = R._getPath[o.type](o);
+                o._.dirty = 1;
+            }
+            params.href && (node.href = params.href);
+            params.title && (node.title = params.title);
+            params.target && (node.target = params.target);
+            params.cursor && (s.cursor = params.cursor);
+            "blur" in params && o.blur(params.blur);
+            if (params.path && o.type == "path" || newpath) {
+                node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
+                o._.dirty = 1;
+                if (o.type == "image") {
+                    o._.fillpos = [a.x, a.y];
+                    o._.fillsize = [a.width, a.height];
+                    setCoords(o, 1, 1, 0, 0, 0);
+                }
+            }
+            "transform" in params && o.transform(params.transform);
+            if (isOval) {
+                var cx = +a.cx,
+                    cy = +a.cy,
+                    rx = +a.rx || +a.r || 0,
+                    ry = +a.ry || +a.r || 0;
+                node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom));
+                o._.dirty = 1;
+            }
+            if ("clip-rect" in params) {
+                var rect = Str(params["clip-rect"]).split(separator);
+                if (rect.length == 4) {
+                    rect[2] = +rect[2] + (+rect[0]);
+                    rect[3] = +rect[3] + (+rect[1]);
+                    var div = node.clipRect || R._g.doc.createElement("div"),
+                        dstyle = div.style;
+                    dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
+                    if (!node.clipRect) {
+                        dstyle.position = "absolute";
+                        dstyle.top = 0;
+                        dstyle.left = 0;
+                        dstyle.width = o.paper.width + "px";
+                        dstyle.height = o.paper.height + "px";
+                        node.parentNode.insertBefore(div, node);
+                        div.appendChild(node);
+                        node.clipRect = div;
+                    }
+                }
+                if (!params["clip-rect"]) {
+                    node.clipRect && (node.clipRect.style.clip = "auto");
+                }
+            }
+            if (o.textpath) {
+                var textpathStyle = o.textpath.style;
+                params.font && (textpathStyle.font = params.font);
+                params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
+                params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
+                params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
+                params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
+            }
+            if ("arrow-start" in params) {
+                addArrow(res, params["arrow-start"]);
+            }
+            if ("arrow-end" in params) {
+                addArrow(res, params["arrow-end"], 1);
+            }
+            if (params.opacity != null ||
+                params["stroke-width"] != null ||
+                params.fill != null ||
+                params.src != null ||
+                params.stroke != null ||
+                params["stroke-width"] != null ||
+                params["stroke-opacity"] != null ||
+                params["fill-opacity"] != null ||
+                params["stroke-dasharray"] != null ||
+                params["stroke-miterlimit"] != null ||
+                params["stroke-linejoin"] != null ||
+                params["stroke-linecap"] != null) {
+                var fill = node.getElementsByTagName(fillString),
+                    newfill = false;
+                fill = fill && fill[0];
+                !fill && (newfill = fill = createNode(fillString));
+                if (o.type == "image" && params.src) {
+                    fill.src = params.src;
+                }
+                params.fill && (fill.on = true);
+                if (fill.on == null || params.fill == "none" || params.fill === null) {
+                    fill.on = false;
+                }
+                if (fill.on && params.fill) {
+                    var isURL = Str(params.fill).match(R._ISURL);
+                    if (isURL) {
+                        fill.parentNode == node && node.removeChild(fill);
+                        fill.rotate = true;
+                        fill.src = isURL[1];
+                        fill.type = "tile";
+                        var bbox = o.getBBox(1);
+                        fill.position = bbox.x + S + bbox.y;
+                        o._.fillpos = [bbox.x, bbox.y];
+
+                        R._preload(isURL[1], function () {
+                            o._.fillsize = [this.offsetWidth, this.offsetHeight];
+                        });
+                    } else {
+                        fill.color = R.getRGB(params.fill).hex;
+                        fill.src = E;
+                        fill.type = "solid";
+                        if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
+                            a.fill = "none";
+                            a.gradient = params.fill;
+                            fill.rotate = false;
+                        }
+                    }
+                }
+                if ("fill-opacity" in params || "opacity" in params) {
+                    var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
+                    opacity = mmin(mmax(opacity, 0), 1);
+                    fill.opacity = opacity;
+                    if (fill.src) {
+                        fill.color = "none";
+                    }
+                }
+                node.appendChild(fill);
+                var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
+                    newstroke = false;
+                !stroke && (newstroke = stroke = createNode("stroke"));
+                if ((params.stroke && params.stroke != "none") ||
+                    params["stroke-width"] ||
+                    params["stroke-opacity"] != null ||
+                    params["stroke-dasharray"] ||
+                    params["stroke-miterlimit"] ||
+                    params["stroke-linejoin"] ||
+                    params["stroke-linecap"]) {
+                    stroke.on = true;
+                }
+                (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
+                var strokeColor = R.getRGB(params.stroke);
+                stroke.on && params.stroke && (stroke.color = strokeColor.hex);
+                opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
+                var width = (toFloat(params["stroke-width"]) || 1) * .75;
+                opacity = mmin(mmax(opacity, 0), 1);
+                params["stroke-width"] == null && (width = a["stroke-width"]);
+                params["stroke-width"] && (stroke.weight = width);
+                width && width < 1 && (opacity *= width) && (stroke.weight = 1);
+                stroke.opacity = opacity;
+
+                params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
+                stroke.miterlimit = params["stroke-miterlimit"] || 8;
+                params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
+                if ("stroke-dasharray" in params) {
+                    var dasharray = {
+                        "-": "shortdash",
+                        ".": "shortdot",
+                        "-.": "shortdashdot",
+                        "-..": "shortdashdotdot",
+                        ". ": "dot",
+                        "- ": "dash",
+                        "--": "longdash",
+                        "- .": "dashdot",
+                        "--.": "longdashdot",
+                        "--..": "longdashdotdot"
+                    };
+                    stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
+                }
+                newstroke && node.appendChild(stroke);
+            }
+            if (res.type == "text") {
+                res.paper.canvas.style.display = E;
+                var span = res.paper.span,
+                    m = 100,
+                    fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
+                s = span.style;
+                a.font && (s.font = a.font);
+                a["font-family"] && (s.fontFamily = a["font-family"]);
+                a["font-weight"] && (s.fontWeight = a["font-weight"]);
+                a["font-style"] && (s.fontStyle = a["font-style"]);
+                fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10;
+                s.fontSize = fontSize * m + "px";
+                res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
+                var brect = span.getBoundingClientRect();
+                res.W = a.w = (brect.right - brect.left) / m;
+                res.H = a.h = (brect.bottom - brect.top) / m;
+                // res.paper.canvas.style.display = "none";
+                res.X = a.x;
+                res.Y = a.y + res.H / 2;
+
+                ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1));
+                var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
+                for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
+                    res._.dirty = 1;
+                    break;
+                }
+
+                // text-anchor emulation
+                switch (a["text-anchor"]) {
+                    case "start":
+                        res.textpath.style["v-text-align"] = "left";
+                        res.bbx = res.W / 2;
+                        break;
+                    case "end":
+                        res.textpath.style["v-text-align"] = "right";
+                        res.bbx = -res.W / 2;
+                        break;
+                    default:
+                        res.textpath.style["v-text-align"] = "center";
+                        res.bbx = 0;
+                        break;
+                }
+                res.textpath.style["v-text-kern"] = true;
+            }
+            // res.paper.canvas.style.display = E;
+        },
+        addGradientFill = function (o, gradient, fill) {
+            o.attrs = o.attrs || {};
+            var attrs = o.attrs,
+                pow = Math.pow,
+                opacity,
+                oindex,
+                type = "linear",
+                fxfy = ".5 .5";
+            o.attrs.gradient = gradient;
+            gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
+                type = "radial";
+                if (fx && fy) {
+                    fx = toFloat(fx);
+                    fy = toFloat(fy);
+                    pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
+                    fxfy = fx + S + fy;
+                }
+                return E;
+            });
+            gradient = gradient.split(/\s*\-\s*/);
+            if (type == "linear") {
+                var angle = gradient.shift();
+                angle = -toFloat(angle);
+                if (isNaN(angle)) {
+                    return null;
+                }
+            }
+            var dots = R._parseDots(gradient);
+            if (!dots) {
+                return null;
+            }
+            o = o.shape || o.node;
+            if (dots.length) {
+                o.removeChild(fill);
+                fill.on = true;
+                fill.method = "none";
+                fill.color = dots[0].color;
+                fill.color2 = dots[dots.length - 1].color;
+                var clrs = [];
+                for (var i = 0, ii = dots.length; i < ii; i++) {
+                    dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
+                }
+                fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
+                if (type == "radial") {
+                    fill.type = "gradientTitle";
+                    fill.focus = "100%";
+                    fill.focussize = "0 0";
+                    fill.focusposition = fxfy;
+                    fill.angle = 0;
+                } else {
+                    // fill.rotate= true;
+                    fill.type = "gradient";
+                    fill.angle = (270 - angle) % 360;
+                }
+                o.appendChild(fill);
+            }
+            return 1;
+        },
+        Element = function (node, vml) {
+            this[0] = this.node = node;
+            node.raphael = true;
+            this.id = R._oid++;
+            node.raphaelid = this.id;
+            this.X = 0;
+            this.Y = 0;
+            this.attrs = {};
+            this.paper = vml;
+            this.matrix = R.matrix();
+            this._ = {
+                transform: [],
+                sx: 1,
+                sy: 1,
+                dx: 0,
+                dy: 0,
+                deg: 0,
+                dirty: 1,
+                dirtyT: 1
+            };
+            !vml.bottom && (vml.bottom = this);
+            this.prev = vml.top;
+            vml.top && (vml.top.next = this);
+            vml.top = this;
+            this.next = null;
+        };
+    var elproto = R.el;
+
+    Element.prototype = elproto;
+    elproto.constructor = Element;
+    elproto.transform = function (tstr) {
+        if (tstr == null) {
+            return this._.transform;
+        }
+        var vbs = this.paper._viewBoxShift,
+            vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
+            oldt;
+        if (vbs) {
+            oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
+        }
+        R._extractTransform(this, vbt + tstr);
+        var matrix = this.matrix.clone(),
+            skew = this.skew,
+            o = this.node,
+            split,
+            isGrad = ~Str(this.attrs.fill).indexOf("-"),
+            isPatt = !Str(this.attrs.fill).indexOf("url(");
+        matrix.translate(1, 1);
+        if (isPatt || isGrad || this.type == "image") {
+            skew.matrix = "1 0 0 1";
+            skew.offset = "0 0";
+            split = matrix.split();
+            if ((isGrad && split.noRotation) || !split.isSimple) {
+                o.style.filter = matrix.toFilter();
+                var bb = this.getBBox(),
+                    bbt = this.getBBox(1),
+                    dx = bb.x - bbt.x,
+                    dy = bb.y - bbt.y;
+                o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
+                setCoords(this, 1, 1, dx, dy, 0);
+            } else {
+                o.style.filter = E;
+                setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
+            }
+        } else {
+            o.style.filter = E;
+            skew.matrix = Str(matrix);
+            skew.offset = matrix.offset();
+        }
+        if (oldt !== null) { // empty string value is true as well
+            this._.transform = oldt;
+            R._extractTransform(this, oldt);
+        }
+        return this;
+    };
+    elproto.rotate = function (deg, cx, cy) {
+        if (this.removed) {
+            return this;
+        }
+        if (deg == null) {
+            return;
+        }
+        deg = Str(deg).split(separator);
+        if (deg.length - 1) {
+            cx = toFloat(deg[1]);
+            cy = toFloat(deg[2]);
+        }
+        deg = toFloat(deg[0]);
+        (cy == null) && (cx = cy);
+        if (cx == null || cy == null) {
+            var bbox = this.getBBox(1);
+            cx = bbox.x + bbox.width / 2;
+            cy = bbox.y + bbox.height / 2;
+        }
+        this._.dirtyT = 1;
+        this.transform(this._.transform.concat([["r", deg, cx, cy]]));
+        return this;
+    };
+    elproto.translate = function (dx, dy) {
+        if (this.removed) {
+            return this;
+        }
+        dx = Str(dx).split(separator);
+        if (dx.length - 1) {
+            dy = toFloat(dx[1]);
+        }
+        dx = toFloat(dx[0]) || 0;
+        dy = +dy || 0;
+        if (this._.bbox) {
+            this._.bbox.x += dx;
+            this._.bbox.y += dy;
+        }
+        this.transform(this._.transform.concat([["t", dx, dy]]));
+        return this;
+    };
+    elproto.scale = function (sx, sy, cx, cy) {
+        if (this.removed) {
+            return this;
+        }
+        sx = Str(sx).split(separator);
+        if (sx.length - 1) {
+            sy = toFloat(sx[1]);
+            cx = toFloat(sx[2]);
+            cy = toFloat(sx[3]);
+            isNaN(cx) && (cx = null);
+            isNaN(cy) && (cy = null);
+        }
+        sx = toFloat(sx[0]);
+        (sy == null) && (sy = sx);
+        (cy == null) && (cx = cy);
+        if (cx == null || cy == null) {
+            var bbox = this.getBBox(1);
+        }
+        cx = cx == null ? bbox.x + bbox.width / 2 : cx;
+        cy = cy == null ? bbox.y + bbox.height / 2 : cy;
+
+        this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
+        this._.dirtyT = 1;
+        return this;
+    };
+    elproto.hide = function () {
+        !this.removed && (this.node.style.display = "none");
+        return this;
+    };
+    elproto.show = function () {
+        !this.removed && (this.node.style.display = E);
+        return this;
+    };
+    // Needed to fix the vml setViewBox issues
+    elproto.auxGetBBox = R.el.getBBox;
+    elproto.getBBox = function(){
+        var b = this.auxGetBBox();
+        if (this.paper && this.paper._viewBoxShift)
+        {
+            var c = {};
+            var z = 1/this.paper._viewBoxShift.scale;
+            c.x = b.x - this.paper._viewBoxShift.dx;
+            c.x *= z;
+            c.y = b.y - this.paper._viewBoxShift.dy;
+            c.y *= z;
+            c.width  = b.width  * z;
+            c.height = b.height * z;
+            c.x2 = c.x + c.width;
+            c.y2 = c.y + c.height;
+            return c;
+        }
+        return b;
+    };
+    elproto._getBBox = function () {
+        if (this.removed) {
+            return {};
+        }
+        return {
+            x: this.X + (this.bbx || 0) - this.W / 2,
+            y: this.Y - this.H,
+            width: this.W,
+            height: this.H
+        };
+    };
+    elproto.remove = function () {
+        if (this.removed || !this.node.parentNode) {
+            return;
+        }
+        this.paper.__set__ && this.paper.__set__.exclude(this);
+        R.eve.unbind("raphael.*.*." + this.id);
+        R._tear(this, this.paper);
+        this.node.parentNode.removeChild(this.node);
+        this.shape && this.shape.parentNode.removeChild(this.shape);
+        for (var i in this) {
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+        }
+        this.removed = true;
+    };
+    elproto.attr = function (name, value) {
+        if (this.removed) {
+            return this;
+        }
+        if (name == null) {
+            var res = {};
+            for (var a in this.attrs) if (this.attrs[has](a)) {
+                res[a] = this.attrs[a];
+            }
+            res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
+            res.transform = this._.transform;
+            return res;
+        }
+        if (value == null && R.is(name, "string")) {
+            if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
+                return this.attrs.gradient;
+            }
+            var names = name.split(separator),
+                out = {};
+            for (var i = 0, ii = names.length; i < ii; i++) {
+                name = names[i];
+                if (name in this.attrs) {
+                    out[name] = this.attrs[name];
+                } else if (R.is(this.paper.customAttributes[name], "function")) {
+                    out[name] = this.paper.customAttributes[name].def;
+                } else {
+                    out[name] = R._availableAttrs[name];
+                }
+            }
+            return ii - 1 ? out : out[names[0]];
+        }
+        if (this.attrs && value == null && R.is(name, "array")) {
+            out = {};
+            for (i = 0, ii = name.length; i < ii; i++) {
+                out[name[i]] = this.attr(name[i]);
+            }
+            return out;
+        }
+        var params;
+        if (value != null) {
+            params = {};
+            params[name] = value;
+        }
+        value == null && R.is(name, "object") && (params = name);
+        for (var key in params) {
+            eve("raphael.attr." + key + "." + this.id, this, params[key]);
+        }
+        if (params) {
+            for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
+                var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
+                this.attrs[key] = params[key];
+                for (var subkey in par) if (par[has](subkey)) {
+                    params[subkey] = par[subkey];
+                }
+            }
+            // this.paper.canvas.style.display = "none";
+            if (params.text && this.type == "text") {
+                this.textpath.string = params.text;
+            }
+            setFillAndStroke(this, params);
+            // this.paper.canvas.style.display = E;
+        }
+        return this;
+    };
+    elproto.toFront = function () {
+        !this.removed && this.node.parentNode.appendChild(this.node);
+        this.paper && this.paper.top != this && R._tofront(this, this.paper);
+        return this;
+    };
+    elproto.toBack = function () {
+        if (this.removed) {
+            return this;
+        }
+        if (this.node.parentNode.firstChild != this.node) {
+            this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
+            R._toback(this, this.paper);
+        }
+        return this;
+    };
+    elproto.insertAfter = function (element) {
+        if (this.removed) {
+            return this;
+        }
+        if (element.constructor == R.st.constructor) {
+            element = element[element.length - 1];
+        }
+        if (element.node.nextSibling) {
+            element.node.parentNode.insertBefore(this.node, element.node.nextSibling);
+        } else {
+            element.node.parentNode.appendChild(this.node);
+        }
+        R._insertafter(this, element, this.paper);
+        return this;
+    };
+    elproto.insertBefore = function (element) {
+        if (this.removed) {
+            return this;
+        }
+        if (element.constructor == R.st.constructor) {
+            element = element[0];
+        }
+        element.node.parentNode.insertBefore(this.node, element.node);
+        R._insertbefore(this, element, this.paper);
+        return this;
+    };
+    elproto.blur = function (size) {
+        var s = this.node.runtimeStyle,
+            f = s.filter;
+        f = f.replace(blurregexp, E);
+        if (+size !== 0) {
+            this.attrs.blur = size;
+            s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
+            s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
+        } else {
+            s.filter = f;
+            s.margin = 0;
+            delete this.attrs.blur;
+        }
+        return this;
+    };
+
+    R._engine.path = function (pathString, vml) {
+        var el = createNode("shape");
+        el.style.cssText = cssDot;
+        el.coordsize = zoom + S + zoom;
+        el.coordorigin = vml.coordorigin;
+        var p = new Element(el, vml),
+            attr = {fill: "none", stroke: "#000"};
+        pathString && (attr.path = pathString);
+        p.type = "path";
+        p.path = [];
+        p.Path = E;
+        setFillAndStroke(p, attr);
+        vml.canvas.appendChild(el);
+        var skew = createNode("skew");
+        skew.on = true;
+        el.appendChild(skew);
+        p.skew = skew;
+        p.transform(E);
+        return p;
+    };
+    R._engine.rect = function (vml, x, y, w, h, r) {
+        var path = R._rectPath(x, y, w, h, r),
+            res = vml.path(path),
+            a = res.attrs;
+        res.X = a.x = x;
+        res.Y = a.y = y;
+        res.W = a.width = w;
+        res.H = a.height = h;
+        a.r = r;
+        a.path = path;
+        res.type = "rect";
+        return res;
+    };
+    R._engine.ellipse = function (vml, x, y, rx, ry) {
+        var res = vml.path(),
+            a = res.attrs;
+        res.X = x - rx;
+        res.Y = y - ry;
+        res.W = rx * 2;
+        res.H = ry * 2;
+        res.type = "ellipse";
+        setFillAndStroke(res, {
+            cx: x,
+            cy: y,
+            rx: rx,
+            ry: ry
+        });
+        return res;
+    };
+    R._engine.circle = function (vml, x, y, r) {
+        var res = vml.path(),
+            a = res.attrs;
+        res.X = x - r;
+        res.Y = y - r;
+        res.W = res.H = r * 2;
+        res.type = "circle";
+        setFillAndStroke(res, {
+            cx: x,
+            cy: y,
+            r: r
+        });
+        return res;
+    };
+    R._engine.image = function (vml, src, x, y, w, h) {
+        var path = R._rectPath(x, y, w, h),
+            res = vml.path(path).attr({stroke: "none"}),
+            a = res.attrs,
+            node = res.node,
+            fill = node.getElementsByTagName(fillString)[0];
+        a.src = src;
+        res.X = a.x = x;
+        res.Y = a.y = y;
+        res.W = a.width = w;
+        res.H = a.height = h;
+        a.path = path;
+        res.type = "image";
+        fill.parentNode == node && node.removeChild(fill);
+        fill.rotate = true;
+        fill.src = src;
+        fill.type = "tile";
+        res._.fillpos = [x, y];
+        res._.fillsize = [w, h];
+        node.appendChild(fill);
+        setCoords(res, 1, 1, 0, 0, 0);
+        return res;
+    };
+    R._engine.text = function (vml, x, y, text) {
+        var el = createNode("shape"),
+            path = createNode("path"),
+            o = createNode("textpath");
+        x = x || 0;
+        y = y || 0;
+        text = text || "";
+        path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
+        path.textpathok = true;
+        o.string = Str(text);
+        o.on = true;
+        el.style.cssText = cssDot;
+        el.coordsize = zoom + S + zoom;
+        el.coordorigin = "0 0";
+        var p = new Element(el, vml),
+            attr = {
+                fill: "#000",
+                stroke: "none",
+                font: R._availableAttrs.font,
+                text: text
+            };
+        p.shape = el;
+        p.path = path;
+        p.textpath = o;
+        p.type = "text";
+        p.attrs.text = Str(text);
+        p.attrs.x = x;
+        p.attrs.y = y;
+        p.attrs.w = 1;
+        p.attrs.h = 1;
+        setFillAndStroke(p, attr);
+        el.appendChild(o);
+        el.appendChild(path);
+        vml.canvas.appendChild(el);
+        var skew = createNode("skew");
+        skew.on = true;
+        el.appendChild(skew);
+        p.skew = skew;
+        p.transform(E);
+        return p;
+    };
+    R._engine.setSize = function (width, height) {
+        var cs = this.canvas.style;
+        this.width = width;
+        this.height = height;
+        width == +width && (width += "px");
+        height == +height && (height += "px");
+        cs.width = width;
+        cs.height = height;
+        cs.clip = "rect(0 " + width + " " + height + " 0)";
+        if (this._viewBox) {
+            R._engine.setViewBox.apply(this, this._viewBox);
+        }
+        return this;
+    };
+    R._engine.setViewBox = function (x, y, w, h, fit) {
+        R.eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
+        var paperSize = this.getSize(),
+            width = paperSize.width,
+            height = paperSize.height,
+            H, W;
+        if (fit) {
+            H = height / h;
+            W = width / w;
+            if (w * H < width) {
+                x -= (width - w * H) / 2 / H;
+            }
+            if (h * W < height) {
+                y -= (height - h * W) / 2 / W;
+            }
+        }
+        this._viewBox = [x, y, w, h, !!fit];
+        this._viewBoxShift = {
+            dx: -x,
+            dy: -y,
+            scale: paperSize
+        };
+        this.forEach(function (el) {
+            el.transform("...");
+        });
+        return this;
+    };
+    var createNode;
+    R._engine.initWin = function (win) {
+        var doc = win.document;
+        if (doc.styleSheets.length < 31) {
+            doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
+        } else {
+            // no more room, add to the existing one
+            // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx
+            doc.styleSheets[0].addRule(".rvml", "behavior:url(#default#VML)");
+        }
+        try {
+            !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
+            createNode = function (tagName) {
+                return doc.createElement('<rvml:' + tagName + ' class="rvml">');
+            };
+        } catch (e) {
+            createNode = function (tagName) {
+                return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
+            };
+        }
+    };
+    R._engine.initWin(R._g.win);
+    R._engine.create = function () {
+        var con = R._getContainer.apply(0, arguments),
+            container = con.container,
+            height = con.height,
+            s,
+            width = con.width,
+            x = con.x,
+            y = con.y;
+        if (!container) {
+            throw new Error("VML container not found.");
+        }
+        var res = new R._Paper,
+            c = res.canvas = R._g.doc.createElement("div"),
+            cs = c.style;
+        x = x || 0;
+        y = y || 0;
+        width = width || 512;
+        height = height || 342;
+        res.width = width;
+        res.height = height;
+        width == +width && (width += "px");
+        height == +height && (height += "px");
+        res.coordsize = zoom * 1e3 + S + zoom * 1e3;
+        res.coordorigin = "0 0";
+        res.span = R._g.doc.createElement("span");
+        res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
+        c.appendChild(res.span);
+        cs.cssText = R.format("top:0;left:0;display:inline-block;position:absolute;clip:rect(0 {0} {1} 0);", width, height);
+        if (container == 1) {
+            R._g.doc.body.appendChild(c);
+            cs.left = x + "px";
+            cs.top = y + "px";
+            cs.position = "absolute";
+        } else {
+            if (container.firstChild) {
+                container.insertBefore(c, container.firstChild);
+            } else {
+                container.appendChild(c);
+            }
+        }
+        res.renderfix = function () {};
+        return res;
+    };
+    R.prototype.clear = function () {
+        R.eve("raphael.clear", this);
+        this.canvas.innerHTML = E;
+        this.span = R._g.doc.createElement("span");
+        this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
+        this.canvas.appendChild(this.span);
+        this.bottom = this.top = null;
+    };
+    R.prototype.remove = function () {
+        R.eve("raphael.remove", this);
+        this.canvas.parentNode.removeChild(this.canvas);
+        for (var i in this) {
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
+        }
+        return true;
+    };
+
+    var setproto = R.st;
+    for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
+        setproto[method] = (function (methodname) {
+            return function () {
+                var arg = arguments;
+                return this.forEach(function (el) {
+                    el[methodname].apply(el, arg);
+                });
+            };
+        })(method);
+    }
+}));
+
+// ┌────────────────────────────────────────────────────────────────────┐ \\
+// │ Raphaël 2.1.4 - JavaScript Vector Library                      │ \\
+// ├────────────────────────────────────────────────────────────────────┤ \\
+// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com)    │ \\
+// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com)              │ \\
+// ├────────────────────────────────────────────────────────────────────┤ \\
+// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\
+// └────────────────────────────────────────────────────────────────────┘ \\
+
+(function (glob, factory) {
+    if (typeof define === "function" && define.amd) {
+        define("raphael", ["raphael.core", "raphael.svg", "raphael.vml"], function(Raphael) {
+            return factory(Raphael);
+        });
+    } else if (typeof exports === "object") {
+        var raphael = require("raphael.core");
+
+        require("raphael.svg");
+        require("raphael.vml");
+
+        module.exports = factory(raphael);
+    } else {
+        //glob.Raphael = factory(glob.Raphael);
+    }
+}(this, function (Raphael) {
+    return Raphael.ninja();
+}));/*
+ * JQuery zTree core v3.5.18
+ * http://zTree.me/
+ *
+ * Copyright (c) 2010 Hunter.z
+ *
+ * Licensed same as jquery - MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * email: hunter.z@263.net
+ * Date: 2015-06-18
+ */
+(function($){
+	var settings = {}, roots = {}, caches = {},
+	//default consts of core
+	_consts = {
+		className: {
+			BUTTON: "button",
+			LEVEL: "level",
+			ICO_LOADING: "ico_loading",
+			SWITCH: "switch"
+		},
+		event: {
+			NODECREATED: "ztree_nodeCreated",
+			CLICK: "ztree_click",
+			EXPAND: "ztree_expand",
+			COLLAPSE: "ztree_collapse",
+			ASYNC_SUCCESS: "ztree_async_success",
+			ASYNC_ERROR: "ztree_async_error",
+			REMOVE: "ztree_remove",
+			SELECTED: "ztree_selected",
+			UNSELECTED: "ztree_unselected"
+		},
+		id: {
+			A: "_a",
+			ICON: "_ico",
+			SPAN: "_span",
+			SWITCH: "_switch",
+			UL: "_ul"
+		},
+		line: {
+			ROOT: "root",
+			ROOTS: "roots",
+			CENTER: "center",
+			BOTTOM: "bottom",
+			NOLINE: "noline",
+			LINE: "line"
+		},
+		folder: {
+			OPEN: "open",
+			CLOSE: "close",
+			DOCU: "docu"
+		},
+		node: {
+			CURSELECTED: "curSelectedNode"
+		}
+	},
+	//default setting of core
+	_setting = {
+		treeId: "",
+		treeObj: null,
+		view: {
+			addDiyDom: null,
+			autoCancelSelected: true,
+			dblClickExpand: true,
+			expandSpeed: "fast",
+			fontCss: {},
+			nameIsHTML: false,
+			selectedMulti: true,
+			showIcon: true,
+			showLine: true,
+			showTitle: true,
+			txtSelectedEnable: false
+		},
+		data: {
+			key: {
+				children: "children",
+				name: "name",
+				title: "",
+				url: "url"
+			},
+			simpleData: {
+				enable: false,
+				idKey: "id",
+				pIdKey: "pId",
+				rootPId: null
+			},
+			keep: {
+				parent: false,
+				leaf: false
+			}
+		},
+		async: {
+			enable: false,
+			contentType: "application/x-www-form-urlencoded",
+			type: "post",
+			dataType: "text",
+			url: "",
+			autoParam: [],
+			otherParam: [],
+			dataFilter: null
+		},
+		callback: {
+			beforeAsync:null,
+			beforeClick:null,
+			beforeDblClick:null,
+			beforeRightClick:null,
+			beforeMouseDown:null,
+			beforeMouseUp:null,
+			beforeExpand:null,
+			beforeCollapse:null,
+			beforeRemove:null,
+
+			onAsyncError:null,
+			onAsyncSuccess:null,
+			onNodeCreated:null,
+			onClick:null,
+			onDblClick:null,
+			onRightClick:null,
+			onMouseDown:null,
+			onMouseUp:null,
+			onExpand:null,
+			onCollapse:null,
+			onRemove:null
+		}
+	},
+	//default root of core
+	//zTree use root to save full data
+	_initRoot = function (setting) {
+		var r = data.getRoot(setting);
+		if (!r) {
+			r = {};
+			data.setRoot(setting, r);
+		}
+		r[setting.data.key.children] = [];
+		r.expandTriggerFlag = false;
+		r.curSelectedList = [];
+		r.noSelection = true;
+		r.createdNodes = [];
+		r.zId = 0;
+		r._ver = (new Date()).getTime();
+	},
+	//default cache of core
+	_initCache = function(setting) {
+		var c = data.getCache(setting);
+		if (!c) {
+			c = {};
+			data.setCache(setting, c);
+		}
+		c.nodes = [];
+		c.doms = [];
+	},
+	//default bindEvent of core
+	_bindEvent = function(setting) {
+		var o = setting.treeObj,
+		c = consts.event;
+		o.bind(c.NODECREATED, function (event, treeId, node) {
+			tools.apply(setting.callback.onNodeCreated, [event, treeId, node]);
+		});
+
+		o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) {
+			tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]);
+		});
+
+		o.bind(c.EXPAND, function (event, treeId, node) {
+			tools.apply(setting.callback.onExpand, [event, treeId, node]);
+		});
+
+		o.bind(c.COLLAPSE, function (event, treeId, node) {
+			tools.apply(setting.callback.onCollapse, [event, treeId, node]);
+		});
+
+		o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) {
+			tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]);
+		});
+
+		o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) {
+			tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]);
+		});
+
+		o.bind(c.REMOVE, function (event, treeId, treeNode) {
+			tools.apply(setting.callback.onRemove, [event, treeId, treeNode]);
+		});
+
+		o.bind(c.SELECTED, function (event, srcEvent, treeId, node) {
+			tools.apply(setting.callback.onSelected, [srcEvent, treeId, node]);
+		});
+		o.bind(c.UNSELECTED, function (event, srcEvent, treeId, node) {
+			tools.apply(setting.callback.onUnSelected, [srcEvent, treeId, node]);
+		});
+	},
+	_unbindEvent = function(setting) {
+		var o = setting.treeObj,
+		c = consts.event;
+		o.unbind(c.NODECREATED)
+		.unbind(c.CLICK)
+		.unbind(c.EXPAND)
+		.unbind(c.COLLAPSE)
+		.unbind(c.ASYNC_SUCCESS)
+		.unbind(c.ASYNC_ERROR)
+		.unbind(c.REMOVE)
+		.unbind(c.SELECTED)
+		.unbind(c.UNSELECTED);
+	},
+	//default event proxy of core
+	_eventProxy = function(event) {
+		var target = event.target,
+		setting = data.getSetting(event.data.treeId),
+		tId = "", node = null,
+		nodeEventType = "", treeEventType = "",
+		nodeEventCallback = null, treeEventCallback = null,
+		tmp = null;
+
+		if (tools.eqs(event.type, "mousedown")) {
+			treeEventType = "mousedown";
+		} else if (tools.eqs(event.type, "mouseup")) {
+			treeEventType = "mouseup";
+		} else if (tools.eqs(event.type, "contextmenu")) {
+			treeEventType = "contextmenu";
+		} else if (tools.eqs(event.type, "click")) {
+			if (tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.SWITCH) !== null) {
+				tId = tools.getNodeMainDom(target).id;
+				nodeEventType = "switchNode";
+			} else {
+				tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]);
+				if (tmp) {
+					tId = tools.getNodeMainDom(tmp).id;
+					nodeEventType = "clickNode";
+				}
+			}
+		} else if (tools.eqs(event.type, "dblclick")) {
+			treeEventType = "dblclick";
+			tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]);
+			if (tmp) {
+				tId = tools.getNodeMainDom(tmp).id;
+				nodeEventType = "switchNode";
+			}
+		}
+		if (treeEventType.length > 0 && tId.length == 0) {
+			tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]);
+			if (tmp) {tId = tools.getNodeMainDom(tmp).id;}
+		}
+		// event to node
+		if (tId.length>0) {
+			node = data.getNodeCache(setting, tId);
+			switch (nodeEventType) {
+				case "switchNode" :
+					if (!node.isParent) {
+						nodeEventType = "";
+					} else if (tools.eqs(event.type, "click")
+						|| (tools.eqs(event.type, "dblclick") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) {
+						nodeEventCallback = handler.onSwitchNode;
+					} else {
+						nodeEventType = "";
+					}
+					break;
+				case "clickNode" :
+					nodeEventCallback = handler.onClickNode;
+					break;
+			}
+		}
+		// event to zTree
+		switch (treeEventType) {
+			case "mousedown" :
+				treeEventCallback = handler.onZTreeMousedown;
+				break;
+			case "mouseup" :
+				treeEventCallback = handler.onZTreeMouseup;
+				break;
+			case "dblclick" :
+				treeEventCallback = handler.onZTreeDblclick;
+				break;
+			case "contextmenu" :
+				treeEventCallback = handler.onZTreeContextmenu;
+				break;
+		}
+		var proxyResult = {
+			stop: false,
+			node: node,
+			nodeEventType: nodeEventType,
+			nodeEventCallback: nodeEventCallback,
+			treeEventType: treeEventType,
+			treeEventCallback: treeEventCallback
+		};
+		return proxyResult
+	},
+	//default init node of core
+	_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
+		if (!n) return;
+		var r = data.getRoot(setting),
+		childKey = setting.data.key.children;
+		n.level = level;
+		n.tId = setting.treeId + "_" + (++r.zId);
+		n.parentTId = parentNode ? parentNode.tId : null;
+		n.open = (typeof n.open == "string") ? tools.eqs(n.open, "true") : !!n.open;
+		if (n[childKey] && n[childKey].length > 0) {
+			n.isParent = true;
+			n.zAsync = true;
+		} else {
+			n.isParent = (typeof n.isParent == "string") ? tools.eqs(n.isParent, "true") : !!n.isParent;
+			n.open = (n.isParent && !setting.async.enable) ? n.open : false;
+			n.zAsync = !n.isParent;
+		}
+		n.isFirstNode = isFirstNode;
+		n.isLastNode = isLastNode;
+		n.getParentNode = function() {return data.getNodeCache(setting, n.parentTId);};
+		n.getPreNode = function() {return data.getPreNode(setting, n);};
+		n.getNextNode = function() {return data.getNextNode(setting, n);};
+		n.isAjaxing = false;
+		data.fixPIdKeyValue(setting, n);
+	},
+	_init = {
+		bind: [_bindEvent],
+		unbind: [_unbindEvent],
+		caches: [_initCache],
+		nodes: [_initNode],
+		proxys: [_eventProxy],
+		roots: [_initRoot],
+		beforeA: [],
+		afterA: [],
+		innerBeforeA: [],
+		innerAfterA: [],
+		zTreeTools: []
+	},
+	//method of operate data
+	data = {
+		addNodeCache: function(setting, node) {
+			data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node;
+		},
+		getNodeCacheId: function(tId) {
+			return tId.substring(tId.lastIndexOf("_")+1);
+		},
+		addAfterA: function(afterA) {
+			_init.afterA.push(afterA);
+		},
+		addBeforeA: function(beforeA) {
+			_init.beforeA.push(beforeA);
+		},
+		addInnerAfterA: function(innerAfterA) {
+			_init.innerAfterA.push(innerAfterA);
+		},
+		addInnerBeforeA: function(innerBeforeA) {
+			_init.innerBeforeA.push(innerBeforeA);
+		},
+		addInitBind: function(bindEvent) {
+			_init.bind.push(bindEvent);
+		},
+		addInitUnBind: function(unbindEvent) {
+			_init.unbind.push(unbindEvent);
+		},
+		addInitCache: function(initCache) {
+			_init.caches.push(initCache);
+		},
+		addInitNode: function(initNode) {
+			_init.nodes.push(initNode);
+		},
+		addInitProxy: function(initProxy, isFirst) {
+			if (!!isFirst) {
+				_init.proxys.splice(0,0,initProxy);
+			} else {
+				_init.proxys.push(initProxy);
+			}
+		},
+		addInitRoot: function(initRoot) {
+			_init.roots.push(initRoot);
+		},
+		addNodesData: function(setting, parentNode, nodes) {
+			var childKey = setting.data.key.children;
+			if (!parentNode[childKey]) parentNode[childKey] = [];
+			if (parentNode[childKey].length > 0) {
+				parentNode[childKey][parentNode[childKey].length - 1].isLastNode = false;
+				view.setNodeLineIcos(setting, parentNode[childKey][parentNode[childKey].length - 1]);
+			}
+			parentNode.isParent = true;
+			parentNode[childKey] = parentNode[childKey].concat(nodes);
+		},
+		addSelectedNode: function(setting, node) {
+			var root = data.getRoot(setting);
+			if (!data.isSelectedNode(setting, node)) {
+				root.curSelectedList.push(node);
+			}
+		},
+		addCreatedNode: function(setting, node) {
+			if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {
+				var root = data.getRoot(setting);
+				root.createdNodes.push(node);
+			}
+		},
+		addZTreeTools: function(zTreeTools) {
+			_init.zTreeTools.push(zTreeTools);
+		},
+		exSetting: function(s) {
+			$.extend(true, _setting, s);
+		},
+		fixPIdKeyValue: function(setting, node) {
+			if (setting.data.simpleData.enable) {
+				node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId;
+			}
+		},
+		getAfterA: function(setting, node, array) {
+			for (var i=0, j=_init.afterA.length; i<j; i++) {
+				_init.afterA[i].apply(this, arguments);
+			}
+		},
+		getBeforeA: function(setting, node, array) {
+			for (var i=0, j=_init.beforeA.length; i<j; i++) {
+				_init.beforeA[i].apply(this, arguments);
+			}
+		},
+		getInnerAfterA: function(setting, node, array) {
+			for (var i=0, j=_init.innerAfterA.length; i<j; i++) {
+				_init.innerAfterA[i].apply(this, arguments);
+			}
+		},
+		getInnerBeforeA: function(setting, node, array) {
+			for (var i=0, j=_init.innerBeforeA.length; i<j; i++) {
+				_init.innerBeforeA[i].apply(this, arguments);
+			}
+		},
+		getCache: function(setting) {
+			return caches[setting.treeId];
+		},
+		getNextNode: function(setting, node) {
+			if (!node) return null;
+			var childKey = setting.data.key.children,
+			p = node.parentTId ? node.getParentNode() : data.getRoot(setting);
+			for (var i=0, l=p[childKey].length-1; i<=l; i++) {
+				if (p[childKey][i] === node) {
+					return (i==l ? null : p[childKey][i+1]);
+				}
+			}
+			return null;
+		},
+		getNodeByParam: function(setting, nodes, key, value) {
+			if (!nodes || !key) return null;
+			var childKey = setting.data.key.children;
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (nodes[i][key] == value) {
+					return nodes[i];
+				}
+				var tmp = data.getNodeByParam(setting, nodes[i][childKey], key, value);
+				if (tmp) return tmp;
+			}
+			return null;
+		},
+		getNodeCache: function(setting, tId) {
+			if (!tId) return null;
+			var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)];
+			return n ? n : null;
+		},
+		getNodeName: function(setting, node) {
+			var nameKey = setting.data.key.name;
+			return "" + node[nameKey];
+		},
+		getNodeTitle: function(setting, node) {
+			var t = setting.data.key.title === "" ? setting.data.key.name : setting.data.key.title;
+			return "" + node[t];
+		},
+		getNodes: function(setting) {
+			return data.getRoot(setting)[setting.data.key.children];
+		},
+		getNodesByParam: function(setting, nodes, key, value) {
+			if (!nodes || !key) return [];
+			var childKey = setting.data.key.children,
+			result = [];
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (nodes[i][key] == value) {
+					result.push(nodes[i]);
+				}
+				result = result.concat(data.getNodesByParam(setting, nodes[i][childKey], key, value));
+			}
+			return result;
+		},
+		getNodesByParamFuzzy: function(setting, nodes, key, value) {
+			if (!nodes || !key) return [];
+			var childKey = setting.data.key.children,
+			result = [];
+			value = value.toLowerCase();
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (typeof nodes[i][key] == "string" && nodes[i][key].toLowerCase().indexOf(value)>-1) {
+					result.push(nodes[i]);
+				}
+				result = result.concat(data.getNodesByParamFuzzy(setting, nodes[i][childKey], key, value));
+			}
+			return result;
+		},
+		getNodesByFilter: function(setting, nodes, filter, isSingle, invokeParam) {
+			if (!nodes) return (isSingle ? null : []);
+			var childKey = setting.data.key.children,
+			result = isSingle ? null : [];
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (tools.apply(filter, [nodes[i], invokeParam], false)) {
+					if (isSingle) {return nodes[i];}
+					result.push(nodes[i]);
+				}
+				var tmpResult = data.getNodesByFilter(setting, nodes[i][childKey], filter, isSingle, invokeParam);
+				if (isSingle && !!tmpResult) {return tmpResult;}
+				result = isSingle ? tmpResult : result.concat(tmpResult);
+			}
+			return result;
+		},
+		getPreNode: function(setting, node) {
+			if (!node) return null;
+			var childKey = setting.data.key.children,
+			p = node.parentTId ? node.getParentNode() : data.getRoot(setting);
+			for (var i=0, l=p[childKey].length; i<l; i++) {
+				if (p[childKey][i] === node) {
+					return (i==0 ? null : p[childKey][i-1]);
+				}
+			}
+			return null;
+		},
+		getRoot: function(setting) {
+			return setting ? roots[setting.treeId] : null;
+		},
+		getRoots: function() {
+			return roots;
+		},
+		getSetting: function(treeId) {
+			return settings[treeId];
+		},
+		getSettings: function() {
+			return settings;
+		},
+		getZTreeTools: function(treeId) {
+			var r = this.getRoot(this.getSetting(treeId));
+			return r ? r.treeTools : null;
+		},
+		initCache: function(setting) {
+			for (var i=0, j=_init.caches.length; i<j; i++) {
+				_init.caches[i].apply(this, arguments);
+			}
+		},
+		initNode: function(setting, level, node, parentNode, preNode, nextNode) {
+			for (var i=0, j=_init.nodes.length; i<j; i++) {
+				_init.nodes[i].apply(this, arguments);
+			}
+		},
+		initRoot: function(setting) {
+			for (var i=0, j=_init.roots.length; i<j; i++) {
+				_init.roots[i].apply(this, arguments);
+			}
+		},
+		isSelectedNode: function(setting, node) {
+			var root = data.getRoot(setting);
+			for (var i=0, j=root.curSelectedList.length; i<j; i++) {
+				if(node === root.curSelectedList[i]) return true;
+			}
+			return false;
+		},
+		removeNodeCache: function(setting, node) {
+			var childKey = setting.data.key.children;
+			if (node[childKey]) {
+				for (var i=0, l=node[childKey].length; i<l; i++) {
+					arguments.callee(setting, node[childKey][i]);
+				}
+			}
+			data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null;
+		},
+		removeSelectedNode: function(setting, node) {
+			var root = data.getRoot(setting);
+			for (var i=0, j=root.curSelectedList.length; i<j; i++) {
+				if(node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) {
+					root.curSelectedList.splice(i, 1);
+					i--;j--;
+				}
+			}
+		},
+		setCache: function(setting, cache) {
+			caches[setting.treeId] = cache;
+		},
+		setRoot: function(setting, root) {
+			roots[setting.treeId] = root;
+		},
+		setZTreeTools: function(setting, zTreeTools) {
+			for (var i=0, j=_init.zTreeTools.length; i<j; i++) {
+				_init.zTreeTools[i].apply(this, arguments);
+			}
+		},
+		transformToArrayFormat: function (setting, nodes) {
+			if (!nodes) return [];
+			var childKey = setting.data.key.children,
+			r = [];
+			if (tools.isArray(nodes)) {
+				for (var i=0, l=nodes.length; i<l; i++) {
+					r.push(nodes[i]);
+					if (nodes[i][childKey])
+						r = r.concat(data.transformToArrayFormat(setting, nodes[i][childKey]));
+				}
+			} else {
+				r.push(nodes);
+				if (nodes[childKey])
+					r = r.concat(data.transformToArrayFormat(setting, nodes[childKey]));
+			}
+			return r;
+		},
+		transformTozTreeFormat: function(setting, sNodes) {
+			var i,l,
+			key = setting.data.simpleData.idKey,
+			parentKey = setting.data.simpleData.pIdKey,
+			childKey = setting.data.key.children;
+			if (!key || key=="" || !sNodes) return [];
+
+			if (tools.isArray(sNodes)) {
+				var r = [];
+				var tmpMap = [];
+				for (i=0, l=sNodes.length; i<l; i++) {
+					tmpMap[sNodes[i][key]] = sNodes[i];
+				}
+				for (i=0, l=sNodes.length; i<l; i++) {
+					if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {
+						if (!tmpMap[sNodes[i][parentKey]][childKey])
+							tmpMap[sNodes[i][parentKey]][childKey] = [];
+						tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);
+					} else {
+						r.push(sNodes[i]);
+					}
+				}
+				return r;
+			}else {
+				return [sNodes];
+			}
+		}
+	},
+	//method of event proxy
+	event = {
+		bindEvent: function(setting) {
+			for (var i=0, j=_init.bind.length; i<j; i++) {
+				_init.bind[i].apply(this, arguments);
+			}
+		},
+		unbindEvent: function(setting) {
+			for (var i=0, j=_init.unbind.length; i<j; i++) {
+				_init.unbind[i].apply(this, arguments);
+			}
+		},
+		bindTree: function(setting) {
+			var eventParam = {
+				treeId: setting.treeId
+			},
+			o = setting.treeObj;
+			if (!setting.view.txtSelectedEnable) {
+				// for can't select text
+				o.bind('selectstart', function(e){
+					var node
+					var n = e.originalEvent.srcElement.nodeName.toLowerCase();
+					return (n === "input" || n === "textarea" );
+				}).css({
+					"-moz-user-select":"-moz-none"
+				});
+			}
+			o.bind('click', eventParam, event.proxy);
+			o.bind('dblclick', eventParam, event.proxy);
+			o.bind('mouseover', eventParam, event.proxy);
+			o.bind('mouseout', eventParam, event.proxy);
+			o.bind('mousedown', eventParam, event.proxy);
+			o.bind('mouseup', eventParam, event.proxy);
+			o.bind('contextmenu', eventParam, event.proxy);
+		},
+		unbindTree: function(setting) {
+			var o = setting.treeObj;
+			o.unbind('click', event.proxy)
+			.unbind('dblclick', event.proxy)
+			.unbind('mouseover', event.proxy)
+			.unbind('mouseout', event.proxy)
+			.unbind('mousedown', event.proxy)
+			.unbind('mouseup', event.proxy)
+			.unbind('contextmenu', event.proxy);
+		},
+		doProxy: function(e) {
+			var results = [];
+			for (var i=0, j=_init.proxys.length; i<j; i++) {
+				var proxyResult = _init.proxys[i].apply(this, arguments);
+				results.push(proxyResult);
+				if (proxyResult.stop) {
+					break;
+				}
+			}
+			return results;
+		},
+		proxy: function(e) {
+			var setting = data.getSetting(e.data.treeId);
+			if (!tools.uCanDo(setting, e)) return true;
+			var results = event.doProxy(e),
+			r = true, x = false;
+			for (var i=0, l=results.length; i<l; i++) {
+				var proxyResult = results[i];
+				if (proxyResult.nodeEventCallback) {
+					x = true;
+					r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;
+				}
+				if (proxyResult.treeEventCallback) {
+					x = true;
+					r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;
+				}
+			}
+			return r;
+		}
+	},
+	//method of event handler
+	handler = {
+		onSwitchNode: function (event, node) {
+			var setting = data.getSetting(event.data.treeId);
+			if (node.open) {
+				if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true;
+				data.getRoot(setting).expandTriggerFlag = true;
+				view.switchNode(setting, node);
+			} else {
+				if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true;
+				data.getRoot(setting).expandTriggerFlag = true;
+				view.switchNode(setting, node);
+			}
+			return true;
+		},
+		onClickNode: function (event, node) {
+			var setting = data.getSetting(event.data.treeId),
+			clickFlag = ( (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1;
+			if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true;
+			if (clickFlag === 0) {
+				view.cancelPreSelectedNode(setting, node);
+			} else {
+				view.selectNode(setting, node, clickFlag === 2);
+			}
+			setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]);
+			return true;
+		},
+		onZTreeMousedown: function(event, node) {
+			var setting = data.getSetting(event.data.treeId);
+			if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) {
+				tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]);
+			}
+			return true;
+		},
+		onZTreeMouseup: function(event, node) {
+			var setting = data.getSetting(event.data.treeId);
+			if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) {
+				tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]);
+			}
+			return true;
+		},
+		onZTreeDblclick: function(event, node) {
+			var setting = data.getSetting(event.data.treeId);
+			if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) {
+				tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]);
+			}
+			return true;
+		},
+		onZTreeContextmenu: function(event, node) {
+			var setting = data.getSetting(event.data.treeId);
+			if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) {
+				tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]);
+			}
+			return (typeof setting.callback.onRightClick) != "function";
+		}
+	},
+	//method of tools for zTree
+	tools = {
+		apply: function(fun, param, defaultValue) {
+			if ((typeof fun) == "function") {
+				return fun.apply(zt, param?param:[]);
+			}
+			return defaultValue;
+		},
+		canAsync: function(setting, node) {
+			var childKey = setting.data.key.children;
+			return (setting.async.enable && node && node.isParent && !(node.zAsync || (node[childKey] && node[childKey].length > 0)));
+		},
+		clone: function (obj){
+			if (obj === null) return null;
+			var o = tools.isArray(obj) ? [] : {};
+			for(var i in obj){
+				o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? arguments.callee(obj[i]) : obj[i]);
+			}
+			return o;
+		},
+		eqs: function(str1, str2) {
+			return str1.toLowerCase() === str2.toLowerCase();
+		},
+		isArray: function(arr) {
+			return Object.prototype.toString.apply(arr) === "[object Array]";
+		},
+		$: function(node, exp, setting) {
+			if (!!exp && typeof exp != "string") {
+				setting = exp;
+				exp = "";
+			}
+			if (typeof node == "string") {
+				return $(node, setting ? setting.treeObj.get(0).ownerDocument : null);
+			} else {
+				return $("#" + node.tId + exp, setting ? setting.treeObj : null);
+			}
+		},
+		getMDom: function (setting, curDom, targetExpr) {
+			if (!curDom) return null;
+			while (curDom && curDom.id !== setting.treeId) {
+				for (var i=0, l=targetExpr.length; curDom.tagName && i<l; i++) {
+					if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) {
+						return curDom;
+					}
+				}
+				curDom = curDom.parentNode;
+			}
+			return null;
+		},
+		getNodeMainDom:function(target) {
+			return ($(target).parent("li").get(0) || $(target).parentsUntil("li").parent().get(0));
+		},
+		isChildOrSelf: function(dom, parentId) {
+			return ( $(dom).closest("#" + parentId).length> 0 );
+		},
+		uCanDo: function(setting, e) {
+			return true;
+		}
+	},
+	//method of operate ztree dom
+	view = {
+		addNodes: function(setting, parentNode, newNodes, isSilent) {
+			if (setting.data.keep.leaf && parentNode && !parentNode.isParent) {
+				return;
+			}
+			if (!tools.isArray(newNodes)) {
+				newNodes = [newNodes];
+			}
+			if (setting.data.simpleData.enable) {
+				newNodes = data.transformTozTreeFormat(setting, newNodes);
+			}
+			if (parentNode) {
+				var target_switchObj = $$(parentNode, consts.id.SWITCH, setting),
+				target_icoObj = $$(parentNode, consts.id.ICON, setting),
+				target_ulObj = $$(parentNode, consts.id.UL, setting);
+
+				if (!parentNode.open) {
+					view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE);
+					view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE);
+					parentNode.open = false;
+					target_ulObj.css({
+						"display": "none"
+					});
+				}
+
+				data.addNodesData(setting, parentNode, newNodes);
+				view.createNodes(setting, parentNode.level + 1, newNodes, parentNode);
+				if (!isSilent) {
+					view.expandCollapseParentNode(setting, parentNode, true);
+				}
+			} else {
+				data.addNodesData(setting, data.getRoot(setting), newNodes);
+				view.createNodes(setting, 0, newNodes, null);
+			}
+		},
+		appendNodes: function(setting, level, nodes, parentNode, initFlag, openFlag) {
+			if (!nodes) return [];
+			var html = [],
+			childKey = setting.data.key.children;
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				var node = nodes[i];
+				if (initFlag) {
+					var tmpPNode = (parentNode) ? parentNode: data.getRoot(setting),
+					tmpPChild = tmpPNode[childKey],
+					isFirstNode = ((tmpPChild.length == nodes.length) && (i == 0)),
+					isLastNode = (i == (nodes.length - 1));
+					data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag);
+					data.addNodeCache(setting, node);
+				}
+
+				var childHtml = [];
+				if (node[childKey] && node[childKey].length > 0) {
+					//make child html first, because checkType
+					childHtml = view.appendNodes(setting, level + 1, node[childKey], node, initFlag, openFlag && node.open);
+				}
+				if (openFlag) {
+
+					view.makeDOMNodeMainBefore(html, setting, node);
+					view.makeDOMNodeLine(html, setting, node);
+					data.getBeforeA(setting, node, html);
+					view.makeDOMNodeNameBefore(html, setting, node);
+					data.getInnerBeforeA(setting, node, html);
+					view.makeDOMNodeIcon(html, setting, node);
+					data.getInnerAfterA(setting, node, html);
+					view.makeDOMNodeNameAfter(html, setting, node);
+					data.getAfterA(setting, node, html);
+					if (node.isParent && node.open) {
+						view.makeUlHtml(setting, node, html, childHtml.join(''));
+					}
+					view.makeDOMNodeMainAfter(html, setting, node);
+					data.addCreatedNode(setting, node);
+				}
+			}
+			return html;
+		},
+		appendParentULDom: function(setting, node) {
+			var html = [],
+			nObj = $$(node, setting);
+			if (!nObj.get(0) && !!node.parentTId) {
+				view.appendParentULDom(setting, node.getParentNode());
+				nObj = $$(node, setting);
+			}
+			var ulObj = $$(node, consts.id.UL, setting);
+			if (ulObj.get(0)) {
+				ulObj.remove();
+			}
+			var childKey = setting.data.key.children,
+			childHtml = view.appendNodes(setting, node.level+1, node[childKey], node, false, true);
+			view.makeUlHtml(setting, node, html, childHtml.join(''));
+			nObj.append(html.join(''));
+		},
+		asyncNode: function(setting, node, isSilent, callback) {
+			var i, l;
+			if (node && !node.isParent) {
+				tools.apply(callback);
+				return false;
+			} else if (node && node.isAjaxing) {
+				return false;
+			} else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) {
+				tools.apply(callback);
+				return false;
+			}
+			if (node) {
+				node.isAjaxing = true;
+				var icoObj = $$(node, consts.id.ICON, setting);
+				icoObj.attr({"style":"", "class":consts.className.BUTTON + " " + consts.className.ICO_LOADING});
+			}
+
+			var tmpParam = {};
+			for (i = 0, l = setting.async.autoParam.length; node && i < l; i++) {
+				var pKey = setting.async.autoParam[i].split("="), spKey = pKey;
+				if (pKey.length>1) {
+					spKey = pKey[1];
+					pKey = pKey[0];
+				}
+				tmpParam[spKey] = node[pKey];
+			}
+			if (tools.isArray(setting.async.otherParam)) {
+				for (i = 0, l = setting.async.otherParam.length; i < l; i += 2) {
+					tmpParam[setting.async.otherParam[i]] = setting.async.otherParam[i + 1];
+				}
+			} else {
+				for (var p in setting.async.otherParam) {
+					tmpParam[p] = setting.async.otherParam[p];
+				}
+			}
+
+			var _tmpV = data.getRoot(setting)._ver;
+			$.ajax({
+				contentType: setting.async.contentType,
+                cache: false,
+				type: setting.async.type,
+				url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url),
+				data: tmpParam,
+				dataType: setting.async.dataType,
+				success: function(msg) {
+					if (_tmpV != data.getRoot(setting)._ver) {
+						return;
+					}
+					var newNodes = [];
+					try {
+						if (!msg || msg.length == 0) {
+							newNodes = [];
+						} else if (typeof msg == "string") {
+							newNodes = eval("(" + msg + ")");
+						} else {
+							newNodes = msg;
+						}
+					} catch(err) {
+						newNodes = msg;
+					}
+
+					if (node) {
+						node.isAjaxing = null;
+						node.zAsync = true;
+					}
+					view.setNodeLineIcos(setting, node);
+					if (newNodes && newNodes !== "") {
+						newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes);
+						view.addNodes(setting, node, !!newNodes ? tools.clone(newNodes) : [], !!isSilent);
+					} else {
+						view.addNodes(setting, node, [], !!isSilent);
+					}
+					setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]);
+					tools.apply(callback);
+				},
+				error: function(XMLHttpRequest, textStatus, errorThrown) {
+					if (_tmpV != data.getRoot(setting)._ver) {
+						return;
+					}
+					if (node) node.isAjaxing = null;
+					view.setNodeLineIcos(setting, node);
+					setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]);
+				}
+			});
+			return true;
+		},
+		cancelPreSelectedNode: function (setting, node, excludeNode) {
+			var list = data.getRoot(setting).curSelectedList,
+				i, n;
+			for (i=list.length-1; i>=0; i--) {
+				n = list[i];
+				if (node === n || (!node && (!excludeNode || excludeNode !== n))) {
+					$$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED);
+					if (node) {
+						data.removeSelectedNode(setting, node);
+						setting.treeObj.trigger(consts.event.UNSELECTED, [event, setting.treeId, n]);
+						break;
+					} else {
+						list.splice(i, 1);
+						setting.treeObj.trigger(consts.event.UNSELECTED, [event, setting.treeId, n]);
+					}
+				}
+			}
+		},
+		createNodeCallback: function(setting) {
+			if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {
+				var root = data.getRoot(setting);
+				while (root.createdNodes.length>0) {
+					var node = root.createdNodes.shift();
+					tools.apply(setting.view.addDiyDom, [setting.treeId, node]);
+					if (!!setting.callback.onNodeCreated) {
+						setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]);
+					}
+				}
+			}
+		},
+		createNodes: function(setting, level, nodes, parentNode) {
+			if (!nodes || nodes.length == 0) return;
+			var root = data.getRoot(setting),
+			childKey = setting.data.key.children,
+			openFlag = !parentNode || parentNode.open || !!$$(parentNode[childKey][0], setting).get(0);
+			root.createdNodes = [];
+			var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, true, openFlag);
+			if (!parentNode) {
+				setting.treeObj.append(zTreeHtml.join(''));
+			} else {
+				var ulObj = $$(parentNode, consts.id.UL, setting);
+				if (ulObj.get(0)) {
+					ulObj.append(zTreeHtml.join(''));
+				}
+			}
+			view.createNodeCallback(setting);
+		},
+		destroy: function(setting) {
+			if (!setting) return;
+			data.initCache(setting);
+			data.initRoot(setting);
+			event.unbindTree(setting);
+			event.unbindEvent(setting);
+			setting.treeObj.empty();
+			delete settings[setting.treeId];
+		},
+		expandCollapseNode: function(setting, node, expandFlag, animateFlag, callback) {
+			var root = data.getRoot(setting),
+			childKey = setting.data.key.children;
+			if (!node) {
+				tools.apply(callback, []);
+				return;
+			}
+			if (root.expandTriggerFlag) {
+				var _callback = callback;
+				callback = function(){
+					if (_callback) _callback();
+					if (node.open) {
+						setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]);
+					} else {
+						setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]);
+					}
+				};
+				root.expandTriggerFlag = false;
+			}
+			if (!node.open && node.isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (node[childKey] && node[childKey].length>0 && !$$(node[childKey][0], setting).get(0)))) {
+				view.appendParentULDom(setting, node);
+				view.createNodeCallback(setting);
+			}
+			if (node.open == expandFlag) {
+				tools.apply(callback, []);
+				return;
+			}
+			var ulObj = $$(node, consts.id.UL, setting),
+			switchObj = $$(node, consts.id.SWITCH, setting),
+			icoObj = $$(node, consts.id.ICON, setting);
+
+			if (node.isParent) {
+				node.open = !node.open;
+				if (node.iconOpen && node.iconClose) {
+					icoObj.attr("style", view.makeNodeIcoStyle(setting, node));
+				}
+
+				if (node.open) {
+					view.replaceSwitchClass(node, switchObj, consts.folder.OPEN);
+					view.replaceIcoClass(node, icoObj, consts.folder.OPEN);
+					if (animateFlag == false || setting.view.expandSpeed == "") {
+						ulObj.show();
+						tools.apply(callback, []);
+					} else {
+						if (node[childKey] && node[childKey].length > 0) {
+							ulObj.slideDown(setting.view.expandSpeed, callback);
+						} else {
+							ulObj.show();
+							tools.apply(callback, []);
+						}
+					}
+				} else {
+					view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE);
+					view.replaceIcoClass(node, icoObj, consts.folder.CLOSE);
+					if (animateFlag == false || setting.view.expandSpeed == "" || !(node[childKey] && node[childKey].length > 0)) {
+						ulObj.hide();
+						tools.apply(callback, []);
+					} else {
+						ulObj.slideUp(setting.view.expandSpeed, callback);
+					}
+				}
+			} else {
+				tools.apply(callback, []);
+			}
+		},
+		expandCollapseParentNode: function(setting, node, expandFlag, animateFlag, callback) {
+			if (!node) return;
+			if (!node.parentTId) {
+				view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);
+				return;
+			} else {
+				view.expandCollapseNode(setting, node, expandFlag, animateFlag);
+			}
+			if (node.parentTId) {
+				view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback);
+			}
+		},
+		expandCollapseSonNode: function(setting, node, expandFlag, animateFlag, callback) {
+			var root = data.getRoot(setting),
+			childKey = setting.data.key.children,
+			treeNodes = (node) ? node[childKey]: root[childKey],
+			selfAnimateSign = (node) ? false : animateFlag,
+			expandTriggerFlag = data.getRoot(setting).expandTriggerFlag;
+			data.getRoot(setting).expandTriggerFlag = false;
+			if (treeNodes) {
+				for (var i = 0, l = treeNodes.length; i < l; i++) {
+					if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign);
+				}
+			}
+			data.getRoot(setting).expandTriggerFlag = expandTriggerFlag;
+			view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback );
+		},
+		isSelectedNode: function (setting, node) {
+			if (!node) {
+				return false;
+			}
+			var list = data.getRoot(setting).curSelectedList,
+				i;
+			for (i=list.length-1; i>=0; i--) {
+				if (node === list[i]) {
+					return true;
+				}
+			}
+			return false;
+		},
+		makeDOMNodeIcon: function(html, setting, node) {
+			var nameStr = data.getNodeName(setting, node),
+			name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+			html.push("<span id='", node.tId, consts.id.ICON,
+				"' title='' treeNode", consts.id.ICON," class='", view.makeNodeIcoClass(setting, node),
+				"' style='", view.makeNodeIcoStyle(setting, node), "'></span><span id='", node.tId, consts.id.SPAN,
+				"'>",name,"</span>");
+		},
+		makeDOMNodeLine: function(html, setting, node) {
+			html.push("<span id='", node.tId, consts.id.SWITCH,	"' title='' class='", view.makeNodeLineClass(setting, node), "' treeNode", consts.id.SWITCH,"></span>");
+		},
+		makeDOMNodeMainAfter: function(html, setting, node) {
+			html.push("</li>");
+		},
+		makeDOMNodeMainBefore: function(html, setting, node) {
+			html.push("<li id='", node.tId, "' class='", consts.className.LEVEL, node.level,"' tabindex='0' hidefocus='true' treenode>");
+		},
+		makeDOMNodeNameAfter: function(html, setting, node) {
+			html.push("</a>");
+		},
+		makeDOMNodeNameBefore: function(html, setting, node) {
+			var title = data.getNodeTitle(setting, node),
+			url = view.makeNodeUrl(setting, node),
+			fontcss = view.makeNodeFontCss(setting, node),
+			fontStyle = [];
+			for (var f in fontcss) {
+				fontStyle.push(f, ":", fontcss[f], ";");
+			}
+			html.push("<a id='", node.tId, consts.id.A, "' class='", consts.className.LEVEL, node.level,"' treeNode", consts.id.A," onclick=\"", (node.click || ''),
+				"\" ", ((url != null && url.length > 0) ? "href='" + url + "'" : ""), " target='",view.makeNodeTarget(node),"' style='", fontStyle.join(''),
+				"'");
+			if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {html.push("title='", title.replace(/'/g,"&#39;").replace(/</g,'&lt;').replace(/>/g,'&gt;'),"'");}
+			html.push(">");
+		},
+		makeNodeFontCss: function(setting, node) {
+			var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss);
+			return (fontCss && ((typeof fontCss) != "function")) ? fontCss : {};
+		},
+		makeNodeIcoClass: function(setting, node) {
+			var icoCss = ["ico"];
+			if (!node.isAjaxing) {
+				icoCss[0] = (node.iconSkin ? node.iconSkin + "_" : "") + icoCss[0];
+				if (node.isParent) {
+					icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);
+				} else {
+					icoCss.push(consts.folder.DOCU);
+				}
+			}
+			return consts.className.BUTTON + " " + icoCss.join('_');
+		},
+		makeNodeIcoStyle: function(setting, node) {
+			var icoStyle = [];
+			if (!node.isAjaxing) {
+				var icon = (node.isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node.icon;
+				if (icon) icoStyle.push("background:url(", icon, ") 0 0 no-repeat;");
+				if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) {
+					icoStyle.push("width:0px;height:0px;");
+				}
+			}
+			return icoStyle.join('');
+		},
+		makeNodeLineClass: function(setting, node) {
+			var lineClass = [];
+			if (setting.view.showLine) {
+				if (node.level == 0 && node.isFirstNode && node.isLastNode) {
+					lineClass.push(consts.line.ROOT);
+				} else if (node.level == 0 && node.isFirstNode) {
+					lineClass.push(consts.line.ROOTS);
+				} else if (node.isLastNode) {
+					lineClass.push(consts.line.BOTTOM);
+				} else {
+					lineClass.push(consts.line.CENTER);
+				}
+			} else {
+				lineClass.push(consts.line.NOLINE);
+			}
+			if (node.isParent) {
+				lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);
+			} else {
+				lineClass.push(consts.folder.DOCU);
+			}
+			return view.makeNodeLineClassEx(node) + lineClass.join('_');
+		},
+		makeNodeLineClassEx: function(node) {
+			return consts.className.BUTTON + " " + consts.className.LEVEL + node.level + " " + consts.className.SWITCH + " ";
+		},
+		makeNodeTarget: function(node) {
+			return (node.target || "_blank");
+		},
+		makeNodeUrl: function(setting, node) {
+			var urlKey = setting.data.key.url;
+			return node[urlKey] ? node[urlKey] : null;
+		},
+		makeUlHtml: function(setting, node, html, content) {
+			html.push("<ul id='", node.tId, consts.id.UL, "' class='", consts.className.LEVEL, node.level, " ", view.makeUlLineClass(setting, node), "' style='display:", (node.open ? "block": "none"),"'>");
+			html.push(content);
+			html.push("</ul>");
+		},
+		makeUlLineClass: function(setting, node) {
+			return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : "");
+		},
+		removeChildNodes: function(setting, node) {
+			if (!node) return;
+			var childKey = setting.data.key.children,
+			nodes = node[childKey];
+			if (!nodes) return;
+
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				data.removeNodeCache(setting, nodes[i]);
+			}
+			data.removeSelectedNode(setting);
+			delete node[childKey];
+
+			if (!setting.data.keep.parent) {
+				node.isParent = false;
+				node.open = false;
+				var tmp_switchObj = $$(node, consts.id.SWITCH, setting),
+				tmp_icoObj = $$(node, consts.id.ICON, setting);
+				view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU);
+				view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU);
+				$$(node, consts.id.UL, setting).remove();
+			} else {
+				$$(node, consts.id.UL, setting).empty();
+			}
+		},
+		setFirstNode: function(setting, parentNode) {
+			var childKey = setting.data.key.children, childLength = parentNode[childKey].length;
+			if ( childLength > 0) {
+				parentNode[childKey][0].isFirstNode = true;
+			}
+		},
+		setLastNode: function(setting, parentNode) {
+			var childKey = setting.data.key.children, childLength = parentNode[childKey].length;
+			if ( childLength > 0) {
+				parentNode[childKey][childLength - 1].isLastNode = true;
+			}
+		},
+		removeNode: function(setting, node) {
+			var root = data.getRoot(setting),
+			childKey = setting.data.key.children,
+			parentNode = (node.parentTId) ? node.getParentNode() : root;
+
+			node.isFirstNode = false;
+			node.isLastNode = false;
+			node.getPreNode = function() {return null;};
+			node.getNextNode = function() {return null;};
+
+			if (!data.getNodeCache(setting, node.tId)) {
+				return;
+			}
+
+			$$(node, setting).remove();
+			data.removeNodeCache(setting, node);
+			data.removeSelectedNode(setting, node);
+
+			for (var i = 0, l = parentNode[childKey].length; i < l; i++) {
+				if (parentNode[childKey][i].tId == node.tId) {
+					parentNode[childKey].splice(i, 1);
+					break;
+				}
+			}
+			view.setFirstNode(setting, parentNode);
+			view.setLastNode(setting, parentNode);
+
+			var tmp_ulObj,tmp_switchObj,tmp_icoObj,
+			childLength = parentNode[childKey].length;
+
+			//repair nodes old parent
+			if (!setting.data.keep.parent && childLength == 0) {
+				//old parentNode has no child nodes
+				parentNode.isParent = false;
+				parentNode.open = false;
+				tmp_ulObj = $$(parentNode, consts.id.UL, setting);
+				tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting);
+				tmp_icoObj = $$(parentNode, consts.id.ICON, setting);
+				view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU);
+				view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU);
+				tmp_ulObj.css("display", "none");
+
+			} else if (setting.view.showLine && childLength > 0) {
+				//old parentNode has child nodes
+				var newLast = parentNode[childKey][childLength - 1];
+				tmp_ulObj = $$(newLast, consts.id.UL, setting);
+				tmp_switchObj = $$(newLast, consts.id.SWITCH, setting);
+				tmp_icoObj = $$(newLast, consts.id.ICON, setting);
+				if (parentNode == root) {
+					if (parentNode[childKey].length == 1) {
+						//node was root, and ztree has only one root after move node
+						view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT);
+					} else {
+						var tmp_first_switchObj = $$(parentNode[childKey][0], consts.id.SWITCH, setting);
+						view.replaceSwitchClass(parentNode[childKey][0], tmp_first_switchObj, consts.line.ROOTS);
+						view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);
+					}
+				} else {
+					view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);
+				}
+				tmp_ulObj.removeClass(consts.line.LINE);
+			}
+		},
+		replaceIcoClass: function(node, obj, newName) {
+			if (!obj || node.isAjaxing) return;
+			var tmpName = obj.attr("class");
+			if (tmpName == undefined) return;
+			var tmpList = tmpName.split("_");
+			switch (newName) {
+				case consts.folder.OPEN:
+				case consts.folder.CLOSE:
+				case consts.folder.DOCU:
+					tmpList[tmpList.length-1] = newName;
+					break;
+			}
+			obj.attr("class", tmpList.join("_"));
+		},
+		replaceSwitchClass: function(node, obj, newName) {
+			if (!obj) return;
+			var tmpName = obj.attr("class");
+			if (tmpName == undefined) return;
+			var tmpList = tmpName.split("_");
+			switch (newName) {
+				case consts.line.ROOT:
+				case consts.line.ROOTS:
+				case consts.line.CENTER:
+				case consts.line.BOTTOM:
+				case consts.line.NOLINE:
+					tmpList[0] = view.makeNodeLineClassEx(node) + newName;
+					break;
+				case consts.folder.OPEN:
+				case consts.folder.CLOSE:
+				case consts.folder.DOCU:
+					tmpList[1] = newName;
+					break;
+			}
+			obj.attr("class", tmpList.join("_"));
+			if (newName !== consts.folder.DOCU) {
+				obj.removeAttr("disabled");
+			} else {
+				obj.attr("disabled", "disabled");
+			}
+		},
+		selectNode: function(setting, node, addFlag) {
+			if (!addFlag) {
+				view.cancelPreSelectedNode(setting, null, node);
+			}
+			$$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED);
+			data.addSelectedNode(setting, node);
+			setting.treeObj.trigger(consts.event.SELECTED, [event, setting.treeId, node]);
+		},
+		setNodeFontCss: function(setting, treeNode) {
+			var aObj = $$(treeNode, consts.id.A, setting),
+			fontCss = view.makeNodeFontCss(setting, treeNode);
+			if (fontCss) {
+				aObj.css(fontCss);
+			}
+		},
+		setNodeLineIcos: function(setting, node) {
+			if (!node) return;
+			var switchObj = $$(node, consts.id.SWITCH, setting),
+			ulObj = $$(node, consts.id.UL, setting),
+			icoObj = $$(node, consts.id.ICON, setting),
+			ulLine = view.makeUlLineClass(setting, node);
+			if (ulLine.length==0) {
+				ulObj.removeClass(consts.line.LINE);
+			} else {
+				ulObj.addClass(ulLine);
+			}
+			switchObj.attr("class", view.makeNodeLineClass(setting, node));
+			if (node.isParent) {
+				switchObj.removeAttr("disabled");
+			} else {
+				switchObj.attr("disabled", "disabled");
+			}
+			icoObj.removeAttr("style");
+			icoObj.attr("style", view.makeNodeIcoStyle(setting, node));
+			icoObj.attr("class", view.makeNodeIcoClass(setting, node));
+		},
+		setNodeName: function(setting, node) {
+			var title = data.getNodeTitle(setting, node),
+			nObj = $$(node, consts.id.SPAN, setting);
+			nObj.empty();
+			if (setting.view.nameIsHTML) {
+				nObj.html(data.getNodeName(setting, node));
+			} else {
+				nObj.text(data.getNodeName(setting, node));
+			}
+			if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) {
+				var aObj = $$(node, consts.id.A, setting);
+				aObj.attr("title", !title ? "" : title);
+			}
+		},
+		setNodeTarget: function(setting, node) {
+			var aObj = $$(node, consts.id.A, setting);
+			aObj.attr("target", view.makeNodeTarget(node));
+		},
+		setNodeUrl: function(setting, node) {
+			var aObj = $$(node, consts.id.A, setting),
+			url = view.makeNodeUrl(setting, node);
+			if (url == null || url.length == 0) {
+				aObj.removeAttr("href");
+			} else {
+				aObj.attr("href", url);
+			}
+		},
+		switchNode: function(setting, node) {
+			if (node.open || !tools.canAsync(setting, node)) {
+				view.expandCollapseNode(setting, node, !node.open);
+			} else if (setting.async.enable) {
+				if (!view.asyncNode(setting, node)) {
+					view.expandCollapseNode(setting, node, !node.open);
+					return;
+				}
+			} else if (node) {
+				view.expandCollapseNode(setting, node, !node.open);
+			}
+		}
+	};
+	// zTree defind
+	$.fn.zTree = {
+		consts : _consts,
+		_z : {
+			tools: tools,
+			view: view,
+			event: event,
+			data: data
+		},
+		getZTreeObj: function(treeId) {
+			var o = data.getZTreeTools(treeId);
+			return o ? o : null;
+		},
+		destroy: function(treeId) {
+			if (!!treeId && treeId.length > 0) {
+				view.destroy(data.getSetting(treeId));
+			} else {
+				for(var s in settings) {
+					view.destroy(settings[s]);
+				}
+			}
+		},
+		init: function(obj, zSetting, zNodes) {
+			var setting = tools.clone(_setting);
+			$.extend(true, setting, zSetting);
+			setting.treeId = obj.attr("id");
+			setting.treeObj = obj;
+			setting.treeObj.empty();
+			settings[setting.treeId] = setting;
+			//For some older browser,(e.g., ie6)
+			if(typeof document.body.style.maxHeight === "undefined") {
+				setting.view.expandSpeed = "";
+			}
+			data.initRoot(setting);
+			var root = data.getRoot(setting),
+			childKey = setting.data.key.children;
+			zNodes = zNodes ? tools.clone(tools.isArray(zNodes)? zNodes : [zNodes]) : [];
+			if (setting.data.simpleData.enable) {
+				root[childKey] = data.transformTozTreeFormat(setting, zNodes);
+			} else {
+				root[childKey] = zNodes;
+			}
+
+			data.initCache(setting);
+			event.unbindTree(setting);
+			event.bindTree(setting);
+			event.unbindEvent(setting);
+			event.bindEvent(setting);
+
+			var zTreeTools = {
+				setting : setting,
+				addNodes : function(parentNode, newNodes, isSilent) {
+					if (!newNodes) return null;
+					if (!parentNode) parentNode = null;
+					if (parentNode && !parentNode.isParent && setting.data.keep.leaf) return null;
+					var xNewNodes = tools.clone(tools.isArray(newNodes)? newNodes: [newNodes]);
+					function addCallback() {
+						view.addNodes(setting, parentNode, xNewNodes, (isSilent==true));
+					}
+
+					if (tools.canAsync(setting, parentNode)) {
+						view.asyncNode(setting, parentNode, isSilent, addCallback);
+					} else {
+						addCallback();
+					}
+					return xNewNodes;
+				},
+				cancelSelectedNode : function(node) {
+					view.cancelPreSelectedNode(setting, node);
+				},
+				destroy : function() {
+					view.destroy(setting);
+				},
+				expandAll : function(expandFlag) {
+					expandFlag = !!expandFlag;
+					view.expandCollapseSonNode(setting, null, expandFlag, true);
+					return expandFlag;
+				},
+				expandNode : function(node, expandFlag, sonSign, focus, callbackFlag) {
+					if (!node || !node.isParent) return null;
+					if (expandFlag !== true && expandFlag !== false) {
+						expandFlag = !node.open;
+					}
+					callbackFlag = !!callbackFlag;
+
+					if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) {
+						return null;
+					} else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) {
+						return null;
+					}
+					if (expandFlag && node.parentTId) {
+						view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false);
+					}
+					if (expandFlag === node.open && !sonSign) {
+						return null;
+					}
+
+					data.getRoot(setting).expandTriggerFlag = callbackFlag;
+					if (!tools.canAsync(setting, node) && sonSign) {
+						view.expandCollapseSonNode(setting, node, expandFlag, true, function() {
+							if (focus !== false) {try{$$(node, setting).focus().blur();}catch(e){}}
+						});
+					} else {
+						node.open = !expandFlag;
+						view.switchNode(this.setting, node);
+						if (focus !== false) {try{$$(node, setting).focus().blur();}catch(e){}}
+					}
+					return expandFlag;
+				},
+				getNodes : function() {
+					return data.getNodes(setting);
+				},
+				getNodeByParam : function(key, value, parentNode) {
+					if (!key) return null;
+					return data.getNodeByParam(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value);
+				},
+				getNodeByTId : function(tId) {
+					return data.getNodeCache(setting, tId);
+				},
+				getNodesByParam : function(key, value, parentNode) {
+					if (!key) return null;
+					return data.getNodesByParam(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value);
+				},
+				getNodesByParamFuzzy : function(key, value, parentNode) {
+					if (!key) return null;
+					return data.getNodesByParamFuzzy(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value);
+				},
+				getNodesByFilter: function(filter, isSingle, parentNode, invokeParam) {
+					isSingle = !!isSingle;
+					if (!filter || (typeof filter != "function")) return (isSingle ? null : []);
+					return data.getNodesByFilter(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), filter, isSingle, invokeParam);
+				},
+				getNodeIndex : function(node) {
+					if (!node) return null;
+					var childKey = setting.data.key.children,
+					parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
+					for (var i=0, l = parentNode[childKey].length; i < l; i++) {
+						if (parentNode[childKey][i] == node) return i;
+					}
+					return -1;
+				},
+				getSelectedNodes : function() {
+					var r = [], list = data.getRoot(setting).curSelectedList;
+					for (var i=0, l=list.length; i<l; i++) {
+						r.push(list[i]);
+					}
+					return r;
+				},
+				isSelectedNode : function(node) {
+					return data.isSelectedNode(setting, node);
+				},
+				reAsyncChildNodes : function(parentNode, reloadType, isSilent) {
+					if (!this.setting.async.enable) return;
+					var isRoot = !parentNode;
+					if (isRoot) {
+						parentNode = data.getRoot(setting);
+					}
+					if (reloadType=="refresh") {
+						var childKey = this.setting.data.key.children;
+						for (var i = 0, l = parentNode[childKey] ? parentNode[childKey].length : 0; i < l; i++) {
+							data.removeNodeCache(setting, parentNode[childKey][i]);
+						}
+						data.removeSelectedNode(setting);
+						parentNode[childKey] = [];
+						if (isRoot) {
+							this.setting.treeObj.empty();
+						} else {
+							var ulObj = $$(parentNode, consts.id.UL, setting);
+							ulObj.empty();
+						}
+					}
+					view.asyncNode(this.setting, isRoot? null:parentNode, !!isSilent);
+				},
+				refresh : function() {
+					this.setting.treeObj.empty();
+					var root = data.getRoot(setting),
+					nodes = root[setting.data.key.children]
+					data.initRoot(setting);
+					root[setting.data.key.children] = nodes
+					data.initCache(setting);
+					view.createNodes(setting, 0, root[setting.data.key.children]);
+				},
+				removeChildNodes : function(node) {
+					if (!node) return null;
+					var childKey = setting.data.key.children,
+					nodes = node[childKey];
+					view.removeChildNodes(setting, node);
+					return nodes ? nodes : null;
+				},
+				removeNode : function(node, callbackFlag) {
+					if (!node) return;
+					callbackFlag = !!callbackFlag;
+					if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return;
+					view.removeNode(setting, node);
+					if (callbackFlag) {
+						this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);
+					}
+				},
+				selectNode : function(node, addFlag) {
+					if (!node) return;
+					if (tools.uCanDo(setting)) {
+						addFlag = setting.view.selectedMulti && addFlag;
+						if (node.parentTId) {
+							view.expandCollapseParentNode(setting, node.getParentNode(), true, false, function() {
+								try{$$(node, setting).focus().blur();}catch(e){}
+							});
+						} else {
+							try{$$(node, setting).focus().blur();}catch(e){}
+						}
+						view.selectNode(setting, node, addFlag);
+					}
+				},
+				transformTozTreeNodes : function(simpleNodes) {
+					return data.transformTozTreeFormat(setting, simpleNodes);
+				},
+				transformToArray : function(nodes) {
+					return data.transformToArrayFormat(setting, nodes);
+				},
+				updateNode : function(node, checkTypeFlag) {
+					if (!node) return;
+					var nObj = $$(node, setting);
+					if (nObj.get(0) && tools.uCanDo(setting)) {
+						view.setNodeName(setting, node);
+						view.setNodeTarget(setting, node);
+						view.setNodeUrl(setting, node);
+						view.setNodeLineIcos(setting, node);
+						view.setNodeFontCss(setting, node);
+					}
+				}
+			}
+			root.treeTools = zTreeTools;
+			data.setZTreeTools(setting, zTreeTools);
+
+			if (root[childKey] && root[childKey].length > 0) {
+				view.createNodes(setting, 0, root[childKey]);
+			} else if (setting.async.enable && setting.async.url && setting.async.url !== '') {
+				view.asyncNode(setting);
+			}
+			return zTreeTools;
+		}
+	};
+
+	var zt = $.fn.zTree,
+	$$ = tools.$,
+	consts = zt.consts;
+})(jQuery);/*
+ * JQuery zTree excheck v3.5.18
+ * http://zTree.me/
+ *
+ * Copyright (c) 2010 Hunter.z
+ *
+ * Licensed same as jquery - MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * email: hunter.z@263.net
+ * Date: 2015-06-18
+ */
+(function($){
+	//default consts of excheck
+	var _consts = {
+		event: {
+			CHECK: "ztree_check"
+		},
+		id: {
+			CHECK: "_check"
+		},
+		checkbox: {
+			STYLE: "checkbox",
+			DEFAULT: "chk",
+			DISABLED: "disable",
+			FALSE: "false",
+			TRUE: "true",
+			FULL: "full",
+			PART: "part",
+			FOCUS: "focus"
+		},
+		radio: {
+			STYLE: "radio",
+			TYPE_ALL: "all",
+			TYPE_LEVEL: "level"
+		}
+	},
+	//default setting of excheck
+	_setting = {
+		check: {
+			enable: false,
+			autoCheckTrigger: false,
+			chkStyle: _consts.checkbox.STYLE,
+			nocheckInherit: false,
+			chkDisabledInherit: false,
+			radioType: _consts.radio.TYPE_LEVEL,
+			chkboxType: {
+				"Y": "ps",
+				"N": "ps"
+			}
+		},
+		data: {
+			key: {
+				checked: "checked"
+			}
+		},
+		callback: {
+			beforeCheck:null,
+			onCheck:null
+		}
+	},
+	//default root of excheck
+	_initRoot = function (setting) {
+		var r = data.getRoot(setting);
+		r.radioCheckedList = [];
+	},
+	//default cache of excheck
+	_initCache = function(treeId) {},
+	//default bind event of excheck
+	_bindEvent = function(setting) {
+		var o = setting.treeObj,
+		c = consts.event;
+		o.bind(c.CHECK, function (event, srcEvent, treeId, node) {
+			event.srcEvent = srcEvent;
+			tools.apply(setting.callback.onCheck, [event, treeId, node]);
+		});
+	},
+	_unbindEvent = function(setting) {
+		var o = setting.treeObj,
+		c = consts.event;
+		o.unbind(c.CHECK);
+	},
+	//default event proxy of excheck
+	_eventProxy = function(e) {
+		var target = e.target,
+		setting = data.getSetting(e.data.treeId),
+		tId = "", node = null,
+		nodeEventType = "", treeEventType = "",
+		nodeEventCallback = null, treeEventCallback = null;
+
+		if (tools.eqs(e.type, "mouseover")) {
+			if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
+				tId = tools.getNodeMainDom(target).id;
+				nodeEventType = "mouseoverCheck";
+			}
+		} else if (tools.eqs(e.type, "mouseout")) {
+			if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
+				tId = tools.getNodeMainDom(target).id;
+				nodeEventType = "mouseoutCheck";
+			}
+		} else if (tools.eqs(e.type, "click")) {
+			if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) {
+				tId = tools.getNodeMainDom(target).id;
+				nodeEventType = "checkNode";
+			}
+		}
+		if (tId.length>0) {
+			node = data.getNodeCache(setting, tId);
+			switch (nodeEventType) {
+				case "checkNode" :
+					nodeEventCallback = _handler.onCheckNode;
+					break;
+				case "mouseoverCheck" :
+					nodeEventCallback = _handler.onMouseoverCheck;
+					break;
+				case "mouseoutCheck" :
+					nodeEventCallback = _handler.onMouseoutCheck;
+					break;
+			}
+		}
+		var proxyResult = {
+			stop: nodeEventType === "checkNode",
+			node: node,
+			nodeEventType: nodeEventType,
+			nodeEventCallback: nodeEventCallback,
+			treeEventType: treeEventType,
+			treeEventCallback: treeEventCallback
+		};
+		return proxyResult
+	},
+	//default init node of excheck
+	_initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
+		if (!n) return;
+		var checkedKey = setting.data.key.checked;
+		if (typeof n[checkedKey] == "string") n[checkedKey] = tools.eqs(n[checkedKey], "true");
+		n[checkedKey] = !!n[checkedKey];
+		n.checkedOld = n[checkedKey];
+		if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true");
+		n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);
+		if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true");
+		n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);
+		if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true");
+		n.halfCheck = !!n.halfCheck;
+		n.check_Child_State = -1;
+		n.check_Focus = false;
+		n.getCheckStatus = function() {return data.getCheckStatus(setting, n);};
+
+		if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && n[checkedKey] ) {
+			var r = data.getRoot(setting);
+			r.radioCheckedList.push(n);
+		}
+	},
+	//add dom for check
+	_beforeA = function(setting, node, html) {
+		var checkedKey = setting.data.key.checked;
+		if (setting.check.enable) {
+			data.makeChkFlag(setting, node);
+			html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true?" style='display:none;'":""),"></span>");
+		}
+	},
+	//update zTreeObj, add method of check
+	_zTreeTools = function(setting, zTreeTools) {
+		zTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) {
+			var checkedKey = this.setting.data.key.checked;
+			if (node.chkDisabled === true) return;
+			if (checked !== true && checked !== false) {
+				checked = !node[checkedKey];
+			}
+			callbackFlag = !!callbackFlag;
+
+			if (node[checkedKey] === checked && !checkTypeFlag) {
+				return;
+			} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {
+				return;
+			}
+			if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {
+				node[checkedKey] = checked;
+				var checkObj = $$(node, consts.id.CHECK, this.setting);
+				if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
+				view.setChkClass(this.setting, checkObj, node);
+				view.repairParentChkClassWithSelf(this.setting, node);
+				if (callbackFlag) {
+					this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]);
+				}
+			}
+		}
+
+		zTreeTools.checkAllNodes = function(checked) {
+			view.repairAllChk(this.setting, !!checked);
+		}
+
+		zTreeTools.getCheckedNodes = function(checked) {
+			var childKey = this.setting.data.key.children;
+			checked = (checked !== false);
+			return data.getTreeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey], checked);
+		}
+
+		zTreeTools.getChangeCheckedNodes = function() {
+			var childKey = this.setting.data.key.children;
+			return data.getTreeChangeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey]);
+		}
+
+		zTreeTools.setChkDisabled = function(node, disabled, inheritParent, inheritChildren) {
+			disabled = !!disabled;
+			inheritParent = !!inheritParent;
+			inheritChildren = !!inheritChildren;
+			view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);
+			view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);
+		}
+
+		var _updateNode = zTreeTools.updateNode;
+		zTreeTools.updateNode = function(node, checkTypeFlag) {
+			if (_updateNode) _updateNode.apply(zTreeTools, arguments);
+			if (!node || !this.setting.check.enable) return;
+			var nObj = $$(node, this.setting);
+			if (nObj.get(0) && tools.uCanDo(this.setting)) {
+				var checkObj = $$(node, consts.id.CHECK, this.setting);
+				if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
+				view.setChkClass(this.setting, checkObj, node);
+				view.repairParentChkClassWithSelf(this.setting, node);
+			}
+		}
+	},
+	//method of operate data
+	_data = {
+		getRadioCheckedList: function(setting) {
+			var checkedList = data.getRoot(setting).radioCheckedList;
+			for (var i=0, j=checkedList.length; i<j; i++) {
+				if(!data.getNodeCache(setting, checkedList[i].tId)) {
+					checkedList.splice(i, 1);
+					i--; j--;
+				}
+			}
+			return checkedList;
+		},
+		getCheckStatus: function(setting, node) {
+			if (!setting.check.enable || node.nocheck || node.chkDisabled) return null;
+			var checkedKey = setting.data.key.checked,
+			r = {
+				checked: node[checkedKey],
+				half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (node[checkedKey] ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))
+			};
+			return r;
+		},
+		getTreeCheckedNodes: function(setting, nodes, checked, results) {
+			if (!nodes) return [];
+			var childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked,
+			onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);
+			results = !results ? [] : results;
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] == checked) {
+					results.push(nodes[i]);
+					if(onlyOne) {
+						break;
+					}
+				}
+				data.getTreeCheckedNodes(setting, nodes[i][childKey], checked, results);
+				if(onlyOne && results.length > 0) {
+					break;
+				}
+			}
+			return results;
+		},
+		getTreeChangeCheckedNodes: function(setting, nodes, results) {
+			if (!nodes) return [];
+			var childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked;
+			results = !results ? [] : results;
+			for (var i = 0, l = nodes.length; i < l; i++) {
+				if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] != nodes[i].checkedOld) {
+					results.push(nodes[i]);
+				}
+				data.getTreeChangeCheckedNodes(setting, nodes[i][childKey], results);
+			}
+			return results;
+		},
+		makeChkFlag: function(setting, node) {
+			if (!node) return;
+			var childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked,
+			chkFlag = -1;
+			if (node[childKey]) {
+				for (var i = 0, l = node[childKey].length; i < l; i++) {
+					var cNode = node[childKey][i];
+					var tmp = -1;
+					if (setting.check.chkStyle == consts.radio.STYLE) {
+						if (cNode.nocheck === true || cNode.chkDisabled === true) {
+							tmp = cNode.check_Child_State;
+						} else if (cNode.halfCheck === true) {
+							tmp = 2;
+						} else if (cNode[checkedKey]) {
+							tmp = 2;
+						} else {
+							tmp = cNode.check_Child_State > 0 ? 2:0;
+						}
+						if (tmp == 2) {
+							chkFlag = 2; break;
+						} else if (tmp == 0){
+							chkFlag = 0;
+						}
+					} else if (setting.check.chkStyle == consts.checkbox.STYLE) {
+						if (cNode.nocheck === true || cNode.chkDisabled === true) {
+							tmp = cNode.check_Child_State;
+						} else if (cNode.halfCheck === true) {
+							tmp = 1;
+						} else if (cNode[checkedKey] ) {
+							tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;
+						} else {
+							tmp = (cNode.check_Child_State > 0) ? 1 : 0;
+						}
+						if (tmp === 1) {
+							chkFlag = 1; break;
+						} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {
+							chkFlag = 1; break;
+						} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {
+							chkFlag = 1; break;
+						} else if (tmp > -1) {
+							chkFlag = tmp;
+						}
+					}
+				}
+			}
+			node.check_Child_State = chkFlag;
+		}
+	},
+	//method of event proxy
+	_event = {
+
+	},
+	//method of event handler
+	_handler = {
+		onCheckNode: function (event, node) {
+			if (node.chkDisabled === true) return false;
+			var setting = data.getSetting(event.data.treeId),
+			checkedKey = setting.data.key.checked;
+			if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;
+			node[checkedKey] = !node[checkedKey];
+			view.checkNodeRelation(setting, node);
+			var checkObj = $$(node, consts.id.CHECK, setting);
+			view.setChkClass(setting, checkObj, node);
+			view.repairParentChkClassWithSelf(setting, node);
+			setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);
+			return true;
+		},
+		onMouseoverCheck: function(event, node) {
+			if (node.chkDisabled === true) return false;
+			var setting = data.getSetting(event.data.treeId),
+			checkObj = $$(node, consts.id.CHECK, setting);
+			node.check_Focus = true;
+			view.setChkClass(setting, checkObj, node);
+			return true;
+		},
+		onMouseoutCheck: function(event, node) {
+			if (node.chkDisabled === true) return false;
+			var setting = data.getSetting(event.data.treeId),
+			checkObj = $$(node, consts.id.CHECK, setting);
+			node.check_Focus = false;
+			view.setChkClass(setting, checkObj, node);
+			return true;
+		}
+	},
+	//method of tools for zTree
+	_tools = {
+
+	},
+	//method of operate ztree dom
+	_view = {
+		checkNodeRelation: function(setting, node) {
+			var pNode, i, l,
+			childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked,
+			r = consts.radio;
+			if (setting.check.chkStyle == r.STYLE) {
+				var checkedList = data.getRadioCheckedList(setting);
+				if (node[checkedKey]) {
+					if (setting.check.radioType == r.TYPE_ALL) {
+						for (i = checkedList.length-1; i >= 0; i--) {
+							pNode = checkedList[i];
+							if (pNode[checkedKey] && pNode != node) {
+								pNode[checkedKey] = false;
+								checkedList.splice(i, 1);
+
+								view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
+								if (pNode.parentTId != node.parentTId) {
+									view.repairParentChkClassWithSelf(setting, pNode);
+								}
+							}
+						}
+						checkedList.push(node);
+					} else {
+						var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
+						for (i = 0, l = parentNode[childKey].length; i < l; i++) {
+							pNode = parentNode[childKey][i];
+							if (pNode[checkedKey] && pNode != node) {
+								pNode[checkedKey] = false;
+								view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
+							}
+						}
+					}
+				} else if (setting.check.radioType == r.TYPE_ALL) {
+					for (i = 0, l = checkedList.length; i < l; i++) {
+						if (node == checkedList[i]) {
+							checkedList.splice(i, 1);
+							break;
+						}
+					}
+				}
+
+			} else {
+				if (node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.Y.indexOf("s") > -1)) {
+					view.setSonNodeCheckBox(setting, node, true);
+				}
+				if (!node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.N.indexOf("s") > -1)) {
+					view.setSonNodeCheckBox(setting, node, false);
+				}
+				if (node[checkedKey] && setting.check.chkboxType.Y.indexOf("p") > -1) {
+					view.setParentNodeCheckBox(setting, node, true);
+				}
+				if (!node[checkedKey] && setting.check.chkboxType.N.indexOf("p") > -1) {
+					view.setParentNodeCheckBox(setting, node, false);
+				}
+			}
+		},
+		makeChkClass: function(setting, node) {
+			var checkedKey = setting.data.key.checked,
+			c = consts.checkbox, r = consts.radio,
+			fullStyle = "";
+			if (node.chkDisabled === true) {
+				fullStyle = c.DISABLED;
+			} else if (node.halfCheck) {
+				fullStyle = c.PART;
+			} else if (setting.check.chkStyle == r.STYLE) {
+				fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART;
+			} else {
+				fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART);
+			}
+			var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle;
+			chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName;
+			return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName;
+		},
+		repairAllChk: function(setting, checked) {
+			if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {
+				var checkedKey = setting.data.key.checked,
+				childKey = setting.data.key.children,
+				root = data.getRoot(setting);
+				for (var i = 0, l = root[childKey].length; i<l ; i++) {
+					var node = root[childKey][i];
+					if (node.nocheck !== true && node.chkDisabled !== true) {
+						node[checkedKey] = checked;
+					}
+					view.setSonNodeCheckBox(setting, node, checked);
+				}
+			}
+		},
+		repairChkClass: function(setting, node) {
+			if (!node) return;
+			data.makeChkFlag(setting, node);
+			if (node.nocheck !== true) {
+				var checkObj = $$(node, consts.id.CHECK, setting);
+				view.setChkClass(setting, checkObj, node);
+			}
+		},
+		repairParentChkClass: function(setting, node) {
+			if (!node || !node.parentTId) return;
+			var pNode = node.getParentNode();
+			view.repairChkClass(setting, pNode);
+			view.repairParentChkClass(setting, pNode);
+		},
+		repairParentChkClassWithSelf: function(setting, node) {
+			if (!node) return;
+			var childKey = setting.data.key.children;
+			if (node[childKey] && node[childKey].length > 0) {
+				view.repairParentChkClass(setting, node[childKey][0]);
+			} else {
+				view.repairParentChkClass(setting, node);
+			}
+		},
+		repairSonChkDisabled: function(setting, node, chkDisabled, inherit) {
+			if (!node) return;
+			var childKey = setting.data.key.children;
+			if (node.chkDisabled != chkDisabled) {
+				node.chkDisabled = chkDisabled;
+			}
+			view.repairChkClass(setting, node);
+			if (node[childKey] && inherit) {
+				for (var i = 0, l = node[childKey].length; i < l; i++) {
+					var sNode = node[childKey][i];
+					view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);
+				}
+			}
+		},
+		repairParentChkDisabled: function(setting, node, chkDisabled, inherit) {
+			if (!node) return;
+			if (node.chkDisabled != chkDisabled && inherit) {
+				node.chkDisabled = chkDisabled;
+			}
+			view.repairChkClass(setting, node);
+			view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);
+		},
+		setChkClass: function(setting, obj, node) {
+			if (!obj) return;
+			if (node.nocheck === true) {
+				obj.hide();
+			} else {
+				obj.show();
+			}
+            obj.attr('class', view.makeChkClass(setting, node));
+		},
+		setParentNodeCheckBox: function(setting, node, value, srcNode) {
+			var childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked,
+			checkObj = $$(node, consts.id.CHECK, setting);
+			if (!srcNode) srcNode = node;
+			data.makeChkFlag(setting, node);
+			if (node.nocheck !== true && node.chkDisabled !== true) {
+				node[checkedKey] = value;
+				view.setChkClass(setting, checkObj, node);
+				if (setting.check.autoCheckTrigger && node != srcNode) {
+					setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
+				}
+			}
+			if (node.parentTId) {
+				var pSign = true;
+				if (!value) {
+					var pNodes = node.getParentNode()[childKey];
+					for (var i = 0, l = pNodes.length; i < l; i++) {
+						if ((pNodes[i].nocheck !== true && pNodes[i].chkDisabled !== true && pNodes[i][checkedKey])
+						|| ((pNodes[i].nocheck === true || pNodes[i].chkDisabled === true) && pNodes[i].check_Child_State > 0)) {
+							pSign = false;
+							break;
+						}
+					}
+				}
+				if (pSign) {
+					view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);
+				}
+			}
+		},
+		setSonNodeCheckBox: function(setting, node, value, srcNode) {
+			if (!node) return;
+			var childKey = setting.data.key.children,
+			checkedKey = setting.data.key.checked,
+			checkObj = $$(node, consts.id.CHECK, setting);
+			if (!srcNode) srcNode = node;
+
+			var hasDisable = false;
+			if (node[childKey]) {
+				for (var i = 0, l = node[childKey].length; i < l && node.chkDisabled !== true; i++) {
+					var sNode = node[childKey][i];
+					view.setSonNodeCheckBox(setting, sNode, value, srcNode);
+					if (sNode.chkDisabled === true) hasDisable = true;
+				}
+			}
+
+			if (node != data.getRoot(setting) && node.chkDisabled !== true) {
+				if (hasDisable && node.nocheck !== true) {
+					data.makeChkFlag(setting, node);
+				}
+				if (node.nocheck !== true && node.chkDisabled !== true) {
+					node[checkedKey] = value;
+					if (!hasDisable) node.check_Child_State = (node[childKey] && node[childKey].length > 0) ? (value ? 2 : 0) : -1;
+				} else {
+					node.check_Child_State = -1;
+				}
+				view.setChkClass(setting, checkObj, node);
+				if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {
+					setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
+				}
+			}
+
+		}
+	},
+
+	_z = {
+		tools: _tools,
+		view: _view,
+		event: _event,
+		data: _data
+	};
+	$.extend(true, $.fn.zTree.consts, _consts);
+	$.extend(true, $.fn.zTree._z, _z);
+
+	var zt = $.fn.zTree,
+	tools = zt._z.tools,
+	consts = zt.consts,
+	view = zt._z.view,
+	data = zt._z.data,
+	event = zt._z.event,
+	$$ = tools.$;
+
+	data.exSetting(_setting);
+	data.addInitBind(_bindEvent);
+	data.addInitUnBind(_unbindEvent);
+	data.addInitCache(_initCache);
+	data.addInitNode(_initNode);
+	data.addInitProxy(_eventProxy, true);
+	data.addInitRoot(_initRoot);
+	data.addBeforeA(_beforeA);
+	data.addZTreeTools(_zTreeTools);
+
+	var _createNodes = view.createNodes;
+	view.createNodes = function(setting, level, nodes, parentNode) {
+		if (_createNodes) _createNodes.apply(view, arguments);
+		if (!nodes) return;
+		view.repairParentChkClassWithSelf(setting, parentNode);
+	}
+	var _removeNode = view.removeNode;
+	view.removeNode = function(setting, node) {
+		var parentNode = node.getParentNode();
+		if (_removeNode) _removeNode.apply(view, arguments);
+		if (!node || !parentNode) return;
+		view.repairChkClass(setting, parentNode);
+		view.repairParentChkClass(setting, parentNode);
+	}
+
+	var _appendNodes = view.appendNodes;
+	view.appendNodes = function(setting, level, nodes, parentNode, initFlag, openFlag) {
+		var html = "";
+		if (_appendNodes) {
+			html = _appendNodes.apply(view, arguments);
+		}
+		if (parentNode) {
+			data.makeChkFlag(setting, parentNode);
+		}
+		return html;
+	}
+})(jQuery);/**
+ * 当没有元素时有提示信息的view
+ *
+ * Created by GUY on 2015/9/8.
+ * @class BI.Pane
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.Pane = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Pane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-pane",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            overlap: true,
+            onLoaded: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.Pane.superclass._init.apply(this, arguments);
+    },
+
+    _assertTip: function () {
+        var o = this.options;
+        if (!this._tipText) {
+            this._tipText = BI.createWidget({
+                type: "bi.label",
+                cls: "bi-tips",
+                text: o.tipText,
+                height: 25
+            });
+            BI.createWidget({
+                type: "bi.vertical",
+                element: this,
+                items: [this._tipText],
+                bgap: 25
+            });
+        }
+    },
+
+    loading: function () {
+        var self = this, o = this.options;
+        if (o.overlap === true) {
+            if (!BI.Maskers.has(this.getName())) {
+                BI.createWidget({
+                    type: 'bi.vtape',
+                    items: [{
+                        el: {
+                            type: "bi.layout",
+                            cls: "loading-background"
+                        },
+                        height: 30
+                    }],
+                    element: BI.Maskers.make(this.getName(), this)
+                });
+            }
+            BI.Maskers.show(self.getName());
+        } else {
+            this._loading = BI.createWidget({
+                type: "bi.layout",
+                cls: "loading-background",
+                height: 30
+            });
+            this._loading.element.css("zIndex", 1);
+            BI.createWidget({
+                type: "bi.absolute",
+                element: this,
+                items: [{
+                    el: this._loading,
+                    left: 0,
+                    right: 0,
+                    top: 0
+                }]
+            })
+        }
+    },
+
+    loaded: function () {
+        var self = this, o = this.options;
+        BI.Maskers.remove(self.getName());
+        this._loading && this._loading.destroy();
+        this._loading && (this._loading = null);
+        o.onLoaded();
+        self.fireEvent(BI.Pane.EVENT_LOADED);
+    },
+
+    check: function () {
+        this.setTipVisible(BI.isEmpty(this.options.items));
+    },
+
+    setTipVisible: function (b) {
+        if (b === true) {
+            this._assertTip();
+            this._tipText.setVisible(true);
+        } else {
+            this._tipText && this._tipText.setVisible(false);
+        }
+    },
+
+    populate: function (items) {
+        this.options.items = items || [];
+        this.check();
+    },
+
+    empty: function () {
+
+    }
+});
+BI.Pane.EVENT_LOADED = "EVENT_LOADED";/**
+ * guy
+ * 这仅仅只是一个超类, 所有简单控件的基类
+ * 1、类的控制,
+ * 2、title的控制
+ * 3、文字超过边界显示3个点
+ * 4、cursor默认pointor
+ * @class BI.Single
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.Single = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.Single.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-single",
+            readonly: false,
+            title: null,
+            warningTitle: null,
+            tipType: null, // success或warning
+            value: null
+        })
+    },
+
+    _showToolTip: function (e, opt) {
+        opt || (opt = {});
+        var self = this;
+        var type = this.getTipType() || (this.isEnabled() ? "success" : "warning");
+        var title = type === "success" ? this.getTitle() : (this.getWarningTitle() || this.getTitle());
+        if (BI.isKey(title)) {
+            BI.Tooltips.show(e, this.getName(), title, type, this, opt);
+        }
+    },
+
+    _hideTooltip: function () {
+        var self = this;
+        var tooltip = BI.Tooltips.get(this.getName());
+        if (BI.isNotNull(tooltip)) {
+            tooltip.element.fadeOut(200, function () {
+                BI.Tooltips.remove(self.getName());
+            });
+        }
+    },
+
+    _init: function () {
+        BI.Single.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isKey(o.title) || BI.isKey(o.warningTitle)
+            || BI.isFunction(o.title) || BI.isFunction(o.warningTitle)) {
+            this.enableHover();
+        }
+    },
+
+    enableHover: function (opt) {
+        opt || (opt = {});
+        var self = this;
+        if (!this._hoverBinded) {
+            this.element.on("mouseenter.title" + this.getName(), function (e) {
+                self._e = e;
+                if (self.getTipType() === "warning" || (BI.isKey(self.getWarningTitle()) && !self.isEnabled())) {
+                    self.timeout = BI.delay(function () {
+                        self._showToolTip(self._e || e, opt);
+                    }, 200);
+                } else if (self.getTipType() === "success" || self.isEnabled()) {
+                    self.timeout = BI.delay(function () {
+                        self._showToolTip(self._e || e, opt);
+                    }, 500);
+                }
+            });
+            this.element.on("mousemove.title" + this.getName(), function (e) {
+                self._e = e;
+                if (!self.element.__isMouseInBounds__(e)) {
+                    if (BI.isNotNull(self.timeout)) {
+                        clearTimeout(self.timeout);
+                    }
+                    self._hideTooltip();
+                }
+            });
+            this.element.on("mouseleave.title" + this.getName(), function () {
+                self._e = null;
+                if (BI.isNotNull(self.timeout)) {
+                    clearTimeout(self.timeout);
+                }
+                self._hideTooltip();
+            });
+            this._hoverBinded = true;
+        }
+    },
+
+    disabledHover: function () {
+        //取消hover事件
+        if (BI.isNotNull(this.timeout)) {
+            clearTimeout(this.timeout);
+        }
+        this._hideTooltip();
+        $(this.element).unbind("mouseenter.title" + this.getName())
+            .unbind("mousemove.title" + this.getName())
+            .unbind("mouseleave.title" + this.getName());
+        this._hoverBinded = false;
+    },
+
+    populate: function (items) {
+        this.items = items || [];
+    },
+
+    //opt: {container: '', belowMouse: false}
+    setTitle: function (title, opt) {
+        this.options.title = title;
+        if (BI.isKey(title)) {
+            this.enableHover(opt);
+        } else {
+            this.disabledHover();
+        }
+    },
+
+    setWarningTitle: function (title, opt) {
+        this.options.warningTitle = title;
+        if (BI.isKey(title)) {
+            this.enableHover(opt);
+        } else {
+            this.disabledHover();
+        }
+    },
+
+    getTipType: function () {
+        return this.options.tipType;
+    },
+
+    isReadOnly: function () {
+        return !!this.options.readonly;
+    },
+
+    getTitle: function () {
+        var title = this.options.title;
+        if(BI.isFunction(title)) {
+            return title();
+        }
+        return title;
+    },
+
+    getWarningTitle: function () {
+        var title = this.options.warningTitle;
+        if(BI.isFunction(title)) {
+            return title();
+        }
+        return title;
+    },
+
+    setValue: function (val) {
+        if (!this.options.readonly) {
+            this.options.value = val;
+        }
+    },
+
+    getValue: function () {
+        return this.options.value;
+    }
+});/**
+ * guy 表示一行数据,通过position来定位位置的数据
+ * @class BI.Text
+ * @extends BI.Single
+ */
+BI.Text = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Text.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text",
+            textAlign: "left",
+            whiteSpace: "normal",
+            lineHeight: null,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            text: "",
+            py: ""
+        })
+    },
+
+    _init: function () {
+        BI.Text.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.layout",
+            cls: "bi-text"
+        });
+        this.text.element.appendTo(this.element);
+        if (BI.isKey(o.text)) {
+            this.text.element.text(o.text);
+        } else if (BI.isKey(o.value)) {
+            this.text.element.text(o.value);
+        }
+        if (o.hgap + o.lgap > 0) {
+            this.text.element.css({
+                "margin-left": o.hgap + o.lgap + "px"
+            })
+        }
+        if (o.hgap + o.rgap > 0) {
+            this.text.element.css({
+                "margin-right": o.hgap + o.rgap + "px"
+            })
+        }
+        if (o.vgap + o.tgap > 0) {
+            this.text.element.css({
+                "margin-top": o.vgap + o.tgap + "px"
+            })
+        }
+        if (o.vgap + o.bgap > 0) {
+            this.text.element.css({
+                "margin-bottom": o.vgap + o.bgap + "px"
+            })
+        }
+        if (BI.isNumber(o.height)) {
+            this.element.css({"lineHeight": o.height + "px"});
+        }
+        if (BI.isNumber(o.lineHeight)) {
+            this.element.css({"lineHeight": o.lineHeight + "px"});
+        }
+        this.text.element.css({
+            "textAlign": o.textAlign,
+            "whiteSpace": o.whiteSpace
+        });
+        this.element.css({
+            "textAlign": o.textAlign,
+            "whiteSpace": o.whiteSpace
+        });
+        if (BI.isKey(o.keyword)) {
+            this.text.element.__textKeywordMarked__(o.text, o.keyword, o.py);
+        }
+    },
+
+    doRedMark: function (keyword) {
+        var o = this.options;
+        this.text.element.__textKeywordMarked__(o.text || o.value, keyword, o.py);
+    },
+
+    unRedMark: function () {
+        var o = this.options;
+        this.text.element.__textKeywordMarked__(o.text || o.value, "", o.py);
+    },
+
+    doHighLight: function () {
+        this.text.element.addClass("bi-high-light");
+    },
+
+    unHighLight: function () {
+        this.text.element.removeClass("bi-high-light");
+    },
+
+    setValue: function (text) {
+        BI.Text.superclass.setValue.apply(this, arguments);
+        if (!this.isReadOnly()) {
+            this.text.element.text(text);
+        }
+    },
+
+    setText: function (text) {
+        BI.Text.superclass.setText.apply(this, arguments);
+        this.options.text = text;
+        this.text.element.text(text);
+    }
+});
+
+$.shortcut("bi.text", BI.Text);/**
+ * guy
+ * @class BI.BasicButton
+ * @extends BI.Single
+ *
+ * 一般的button父级
+ */
+BI.BasicButton = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.BasicButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-basic-button cursor-pointer",
+            value: "",
+            text: "",
+            stopEvent: false,
+            stopPropagation: false,
+            selected: false,
+            once: false, //点击一次选中有效,再点无效
+            forceSelected: false, //点击即选中, 选中了就不会被取消
+            forceNotSelected: false, //无论怎么点击都不会被选中
+            disableSelected: false, //使能选中
+
+            shadow: false,
+            isShadowShowingOnSelected: false,  //选中状态下是否显示阴影
+            trigger: null,
+            handler: BI.emptyFn
+        })
+    },
+    _init: function () {
+        BI.BasicButton.superclass._init.apply(this, arguments);
+        var opts = this.options;
+        if (opts.selected === true) {
+            BI.nextTick(BI.bind(function () {
+                this.setSelected(opts.selected);
+            }, this));
+        }
+        BI.nextTick(BI.bind(this.bindEvent, this));
+
+        if (opts.shadow) {
+            this._createShadow();
+        }
+    },
+
+    _createShadow: function () {
+        var self = this, o = this.options;
+
+        var assertMask = function () {
+            if (!self.$mask) {
+                self.$mask = BI.createWidget(BI.isObject(o.shadow) ? o.shadow : {}, {
+                    type: "bi.layout",
+                    cls: "bi-button-mask"
+                });
+                self.$mask.invisible();
+                BI.createWidget({
+                    type: "bi.absolute",
+                    element: self,
+                    items: [{
+                        el: self.$mask,
+                        left: 0,
+                        right: 0,
+                        top: 0,
+                        bottom: 0
+                    }]
+                });
+            }
+        };
+
+        this.element.mouseup(function () {
+            if (!self._hover && !o.isShadowShowingOnSelected) {
+                assertMask();
+                self.$mask.invisible();
+            }
+        });
+        this.element.on("mouseenter." + this.getName(), function (e) {
+            if (self.element.__isMouseInBounds__(e)) {
+                if (self.isEnabled() && !self._hover && (o.isShadowShowingOnSelected || !self.isSelected())) {
+                    assertMask();
+                    self.$mask.visible();
+                }
+            }
+        });
+        this.element.on("mousemove." + this.getName(), function (e) {
+            if (!self.element.__isMouseInBounds__(e)) {
+                if (self.isEnabled() && !self._hover) {
+                    assertMask();
+                    self.$mask.invisible();
+                }
+            }
+        });
+        this.element.on("mouseleave." + this.getName(), function () {
+            if (self.isEnabled() && !self._hover) {
+                assertMask();
+                self.$mask.invisible();
+            }
+        });
+    },
+
+    bindEvent: function () {
+        var self = this;
+        var o = this.options, hand = this.handle();
+        if (!hand) {
+            return;
+        }
+        hand = hand.element;
+        switch (o.trigger) {
+            case "mouseup":
+                var mouseDown = false;
+                hand.mousedown(function () {
+                    mouseDown = true;
+                    ev(e);
+                });
+                hand.mouseup(function (e) {
+                    if (mouseDown === true) {
+                        clk(e);
+                    }
+                    mouseDown = false;
+                    ev(e);
+                });
+                break;
+            case "mousedown":
+                var mouseDown = false;
+                var selected = false;
+                hand.mousedown(function (e) {
+                    // if (e.button === 0) {
+                        if (mouseDown === true) {
+                            return;
+                        }
+                        if (self.isSelected()) {
+                            selected = true;
+                        } else {
+                            clk(e);
+                        }
+                        mouseDown = true;
+                        ev(e);
+                    // }
+                });
+                hand.mouseup(function (e) {
+                    // if (e.button === 0) {
+                        if (mouseDown === true && selected === true) {
+                            clk(e);
+                        }
+                        mouseDown = false;
+                        selected = false;
+                    // }
+                });
+                var checking = BI.debounce(function () {
+                    if (!BI.DOM.isExist(self)) {
+                        $(document).unbind("mouseup." + self.getName());
+                    }
+                }, 3000);
+                $(document).bind("mouseup." + this.getName(), function (e) {
+                    // if (e.button === 0) {
+                        if (BI.DOM.isExist(self)) {
+                            if (!hand.__isMouseInBounds__(e) && mouseDown === true && !selected) {
+                                self.setSelected(!self.isSelected());
+                                self._trigger();
+                            }
+                            mouseDown = false;
+                            checking();
+                        }
+                    // }
+                });
+                break;
+            case "dblclick":
+                hand.dblclick(clk);
+                break;
+            default:
+                hand.mousedown(function (e) {
+                    ev(e);
+                });
+                hand.mouseup(function (e) {
+                    ev(e);
+                });
+                hand.click(clk);
+                break;
+        }
+        //之后的300ms点击无效
+        var onClick = BI.debounce(this.doClick, BI.EVENT_RESPONSE_TIME, true);
+
+        function ev(e) {
+            if (o.stopEvent) {
+                e.stopEvent();
+            }
+            if (o.stopPropagation) {
+                e.stopPropagation();
+            }
+        }
+
+        function clk(e) {
+            ev(e);
+            if (!self.isEnabled() || (self.isOnce() && self.isSelected())) {
+                return;
+            }
+            onClick.apply(self);
+        }
+    },
+
+    _trigger: function () {
+        var o = this.options;
+        if (this.isValid()) {
+            o.handler.call(this, this.getValue(), this);
+            var v = this.getValue();
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, v, this);
+            this.fireEvent(BI.BasicButton.EVENT_CHANGE, v, this);
+        }
+    },
+
+    doClick: function () {
+        if (!this.isDisableSelected()) {
+            this.isForceSelected() ? this.setSelected(true) :
+                (this.isForceNotSelected() ? this.setSelected(false) :
+                    this.setSelected(!this.isSelected()));
+        }
+        this._trigger();
+    },
+
+    handle: function () {
+        return this;
+    },
+
+    hover: function () {
+        this._hover = true;
+        this.handle().element.addClass("hover");
+        if (this.options.shadow) {
+            this.$mask && this.$mask.setVisible(true);
+        }
+    },
+
+    dishover: function () {
+        this._hover = false;
+        this.handle().element.removeClass("hover");
+        if (this.options.shadow) {
+            this.$mask && this.$mask.setVisible(false);
+        }
+    },
+
+    setSelected: function (b) {
+        var o = this.options;
+        o.selected = b;
+        if (this.isSelected()) {
+            this.handle().element.addClass("active");
+        } else {
+            this.handle().element.removeClass("active");
+        }
+        if (o.shadow && !o.isShadowShowingOnSelected) {
+            this.$mask && this.$mask.setVisible(false);
+        }
+    },
+
+    isSelected: function () {
+        return this.options.selected;
+    },
+
+    isOnce: function () {
+        return this.options.once;
+    },
+
+    isForceSelected: function () {
+        return this.options.forceSelected;
+    },
+
+    isForceNotSelected: function () {
+        return this.options.forceNotSelected;
+    },
+
+    isDisableSelected: function () {
+        return this.options.disableSelected;
+    },
+
+    setText: function (text) {
+        this.options.text = text;
+    },
+
+    getText: function () {
+        return this.options.text;
+    },
+
+    setEnable: function (b) {
+        BI.BasicButton.superclass.setEnable.apply(this, arguments);
+        if (!b) {
+            if (this.options.shadow) {
+                this.$mask && this.$mask.setVisible(false);
+            }
+        }
+    },
+
+    empty: function () {
+        $(document).unbind("mouseup." + this.getName());
+        BI.BasicButton.superclass.empty.apply(this, arguments);
+    },
+
+    destroy: function () {
+        BI.BasicButton.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.BasicButton.EVENT_CHANGE = "BasicButton.EVENT_CHANGE";/**
+ * 表示一个可以展开的节点, 不仅有选中状态而且有展开状态
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.NodeButton
+ * @extends BI.BasicButton
+ * @abstract
+ */
+BI.NodeButton = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function() {
+        var conf = BI.NodeButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            baseCls: (conf.baseCls || "") + " bi-node",
+            open: false
+        })
+    },
+
+    _init:function() {
+        BI.NodeButton.superclass._init.apply(this, arguments);
+        var self = this;
+        BI.nextTick(function(){
+            self.setOpened(self.isOpened());
+        })
+    },
+
+    doClick: function(){
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+        this.setOpened(!this.isOpened());
+    },
+
+    isOnce: function(){
+        return false;
+    },
+
+    isOpened: function(){
+        return !!this.options.open;
+    },
+
+    setOpened: function(b){
+        this.options.open = !!b;
+    },
+
+    triggerCollapse: function(){
+        if(this.isOpened()) {
+            this.setOpened(false);
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, this.getValue(), this);
+        }
+    },
+
+    triggerExpand: function(){
+        if(!this.isOpened()) {
+            this.setOpened(true);
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, this.getValue(), this);
+        }
+    }
+});BI.Resizers = new BI.ResizeController();
+BI.Layers = new BI.LayerController();
+BI.Maskers = new BI.MaskersController();
+BI.Bubbles = new BI.BubblesController();
+BI.Tooltips = new BI.TooltipsController();
+BI.Popovers = new BI.FloatBoxController();
+BI.Broadcasts = new BI.BroadcastController();
+/**
+ * canvas绘图
+ *
+ * Created by GUY on 2015/11/18.
+ * @class BI.Canvas
+ * @extends BI.Widget
+ */
+BI.Canvas = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Canvas.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-canvas"
+        })
+    },
+
+    _init: function () {
+        BI.Canvas.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var canvas = document.createElement("canvas");
+        if (!document.createElement('canvas').getContext) {
+            canvas = window.G_vmlCanvasManager.initElement(canvas);
+        }
+        this.element.append(canvas);
+        canvas.width = o.width;
+        canvas.height = o.height;
+        $(canvas).width("100%");
+        $(canvas).height("100%");
+        this.canvas = canvas;
+        this._queue = [];
+    },
+
+    _getContext: function () {
+        if (!this.ctx) {
+            this.ctx = this.canvas.getContext('2d');
+        }
+        return this.ctx;
+    },
+
+    _attr: function (key, value) {
+        var self = this;
+        if (BI.isNull(key)) {
+            return;
+        }
+        if (BI.isObject(key)) {
+            BI.each(key, function (k, v) {
+                self._queue.push({k: k, v: v});
+            });
+            return;
+        }
+        this._queue.push({k: key, v: value});
+    },
+
+    _line: function (x0, y0) {
+        var self = this;
+        var args = [].slice.call(arguments, 2);
+        if (BI.isOdd(args.length)) {
+            this._attr(BI.last(args));
+            args = BI.initial(args);
+        }
+        this._attr("moveTo", [x0, y0]);
+        var odd = BI.filter(args, function (i) {
+            return i % 2 === 0;
+        });
+        var even = BI.filter(args, function (i) {
+            return i % 2 !== 0;
+        });
+        args = BI.zip(odd, even);
+        BI.each(args, function (i, point) {
+            self._attr("lineTo", point);
+        });
+    },
+
+    line: function (x0, y0, x1, y1) {
+        this._line.apply(this, arguments);
+        this._attr("stroke", []);
+    },
+
+    rect: function (x, y, w, h, color) {
+        this._attr("fillStyle", color);
+        this._attr("fillRect", [x, y, w, h]);
+    },
+
+    circle: function (x, y, radius, color) {
+        this._attr({
+            fillStyle: color,
+            beginPath: [],
+            arc: [x, y, radius, 0, Math.PI * 2, true],
+            closePath: [],
+            fill: []
+        });
+    },
+
+    hollow: function () {
+        this._attr("beginPath", []);
+        this._line.apply(this, arguments);
+        this._attr("closePath", []);
+        this._attr("stroke", []);
+    },
+
+    solid: function () {
+        this.hollow.apply(this, arguments);
+        this._attr("fill", []);
+    },
+
+    gradient: function (x0, y0, x1, y1, start, end) {
+        var grd = this._getContext().createLinearGradient(x0, y0, x1, y1);
+        grd.addColorStop(0, start);
+        grd.addColorStop(1, end);
+        return grd;
+    },
+
+    reset: function () {
+        this._getContext().clearRect(0, 0, this.canvas.width, this.canvas.height);
+    },
+
+    stroke: function (callback) {
+        var self = this;
+        BI.nextTick(function () {
+            var ctx = self._getContext();
+            BI.each(self._queue, function (i, q) {
+                if (BI.isFunction(ctx[q.k])) {
+                    ctx[q.k].apply(ctx, q.v);
+                } else {
+                    ctx[q.k] = q.v;
+                }
+            });
+            self._queue = [];
+            callback && callback();
+        });
+    }
+});
+$.shortcut("bi.canvas", BI.Canvas);/**
+ * Collection
+ *
+ * Created by GUY on 2016/1/15.
+ * @class BI.Collection
+ * @extends BI.Widget
+ */
+BI.Collection = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Collection.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-collection",
+            width: 400,
+            height: 300,
+            overflowX: true,
+            overflowY: true,
+            cellSizeAndPositionGetter: BI.emptyFn,
+            horizontalOverscanSize: 0,
+            verticalOverscanSize: 0,
+            scrollLeft: 0,
+            scrollTop: 0,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.Collection.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.renderedCells = [];
+        this.renderedKeys = [];
+        this._scrollLock = false;
+        this._debounceRelease = BI.debounce(function () {
+            self._scrollLock = false;
+        }, 150);
+        this.container = BI.createWidget({
+            type: "bi.absolute"
+        });
+        this.element.scroll(function () {
+            if (self._scrollLock === true) {
+                return;
+            }
+            o.scrollLeft = self.element.scrollLeft();
+            o.scrollTop = self.element.scrollTop();
+            self._calculateChildrenToRender();
+            self.fireEvent(BI.Collection.EVENT_SCROLL, {
+                scrollLeft: o.scrollLeft,
+                scrollTop: o.scrollTop
+            });
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            scrollable: o.overflowX === true && o.overflowY === true,
+            scrolly: o.overflowX === false && o.overflowY === true,
+            scrollx: o.overflowX === true && o.overflowY === false,
+            items: [this.container]
+        });
+        if (o.items.length > 0) {
+            this._calculateSizeAndPositionData();
+            this._populate();
+        }
+    },
+
+    mounted: function () {
+        var o = this.options;
+        if (o.scrollLeft !== 0 || o.scrollTop !== 0) {
+            this.element.scrollTop(o.scrollTop);
+            this.element.scrollLeft(o.scrollLeft);
+        }
+    },
+
+    destroyed: function () {
+        this._debounceRelease = null;
+    },
+
+    _calculateSizeAndPositionData: function () {
+        var o = this.options;
+        var cellMetadata = [];
+        var sectionManager = new BI.SectionManager();
+        var height = 0;
+        var width = 0;
+
+        for (var index = 0, len = o.items.length; index < len; index++) {
+            var cellMetadatum = o.cellSizeAndPositionGetter(index);
+
+            if (
+                cellMetadatum.height == null || isNaN(cellMetadatum.height) ||
+                cellMetadatum.width == null || isNaN(cellMetadatum.width) ||
+                cellMetadatum.x == null || isNaN(cellMetadatum.x) ||
+                cellMetadatum.y == null || isNaN(cellMetadatum.y)
+            ) {
+                throw Error();
+            }
+
+            height = Math.max(height, cellMetadatum.y + cellMetadatum.height);
+            width = Math.max(width, cellMetadatum.x + cellMetadatum.width);
+
+            cellMetadatum.index = index;
+            cellMetadata[index] = cellMetadatum;
+            sectionManager.registerCell(cellMetadatum, index);
+        }
+
+        this._cellMetadata = cellMetadata;
+        this._sectionManager = sectionManager;
+        this._height = height;
+        this._width = width;
+    },
+
+    _cellRenderers: function (height, width, x, y) {
+        this._lastRenderedCellIndices = this._sectionManager.getCellIndices(height, width, x, y);
+        return this._cellGroupRenderer()
+    },
+
+    _cellGroupRenderer: function () {
+        var self = this, o = this.options;
+        var rendered = [];
+        BI.each(this._lastRenderedCellIndices, function (i, index) {
+            var cellMetadata = self._sectionManager.getCellMetadata(index);
+            rendered.push(cellMetadata);
+        });
+        return rendered;
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+        var scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft());
+        var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop());
+        var left = Math.max(0, scrollLeft - o.horizontalOverscanSize);
+        var top = Math.max(0, scrollTop - o.verticalOverscanSize);
+        var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize);
+        var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize);
+        var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top);
+        var renderedCells = [], renderedKeys = [];
+        for (var i = 0, len = childrenToDisplay.length; i < len; i++) {
+            var datum = childrenToDisplay[i];
+            var index = BI.deepIndexOf(this.renderedKeys, datum.index);
+            if (index > -1) {
+                if (datum.width !== this.renderedCells[index]._width) {
+                    this.renderedCells[index]._width = datum.width;
+                    this.renderedCells[index].el.setWidth(datum.width);
+                }
+                if (datum.height !== this.renderedCells[index]._height) {
+                    this.renderedCells[index]._height = datum.height;
+                    this.renderedCells[index].el.setHeight(datum.height);
+                }
+                if (this.renderedCells[index].left !== datum.x) {
+                    this.renderedCells[index].el.element.css("left", datum.x + "px");
+                }
+                if (this.renderedCells[index].top !== datum.y) {
+                    this.renderedCells[index].el.element.css("top", datum.y + "px");
+                }
+                renderedCells.push(this.renderedCells[index]);
+            } else {
+                var child = BI.createWidget(BI.extend({
+                    type: "bi.label",
+                    width: datum.width,
+                    height: datum.height
+                }, o.items[datum.index], {
+                    cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""),
+                    _left: datum.x,
+                    _top: datum.y
+                }));
+                renderedCells.push({
+                    el: child,
+                    left: datum.x,
+                    top: datum.y,
+                    _width: datum.width,
+                    _height: datum.height
+                });
+            }
+            renderedKeys.push(datum.index);
+        }
+        //已存在的, 需要添加的和需要删除的
+        var existSet = {}, addSet = {}, deleteArray = [];
+        BI.each(renderedKeys, function (i, key) {
+            if (BI.deepContains(self.renderedKeys, key)) {
+                existSet[i] = key;
+            } else {
+                addSet[i] = key;
+            }
+        });
+        BI.each(this.renderedKeys, function (i, key) {
+            if (BI.deepContains(existSet, key)) {
+                return;
+            }
+            if (BI.deepContains(addSet, key)) {
+                return;
+            }
+            deleteArray.push(i);
+        });
+        BI.each(deleteArray, function (i, index) {
+            self.renderedCells[index].el.destroy();
+        });
+        var addedItems = [];
+        BI.each(addSet, function (index) {
+            addedItems.push(renderedCells[index])
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: addedItems
+        });
+        this.renderedCells = renderedCells;
+        this.renderedKeys = renderedKeys;
+    },
+
+    _getMaxScrollLeft: function () {
+        return Math.max(0, this._width - this.options.width + (this.options.overflowX ? BI.DOM.getScrollWidth() : 0));
+    },
+
+    _getMaxScrollTop: function () {
+        return Math.max(0, this._height - this.options.height + (this.options.overflowY ? BI.DOM.getScrollWidth() : 0));
+    },
+
+    _populate: function () {
+        var o = this.options;
+        if (o.items.length > 0) {
+            this.container.setWidth(this._width);
+            this.container.setHeight(this._height);
+
+            this._calculateChildrenToRender();
+            this.element.scrollTop(o.scrollTop);
+            this.element.scrollLeft(o.scrollLeft);
+        }
+    },
+
+    setScrollLeft: function (scrollLeft) {
+        if (this.options.scrollLeft === scrollLeft) {
+            return;
+        }
+        this._scrollLock = true;
+        this.options.scrollLeft = BI.clamp(scrollLeft || 0, 0, this._getMaxScrollLeft());
+        this._debounceRelease();
+        this._calculateChildrenToRender();
+        this.element.scrollLeft(this.options.scrollLeft);
+    },
+
+    setScrollTop: function (scrollTop) {
+        if (this.options.scrollTop === scrollTop) {
+            return;
+        }
+        this._scrollLock = true;
+        this.options.scrollTop = BI.clamp(scrollTop || 0, 0, this._getMaxScrollTop());
+        this._debounceRelease();
+        this._calculateChildrenToRender();
+        this.element.scrollTop(this.options.scrollTop);
+    },
+
+    setOverflowX: function (b) {
+        var self = this;
+        if (this.options.overflowX !== !!b) {
+            this.options.overflowX = !!b;
+            BI.nextTick(function () {
+                self.element.css({overflowX: !!b ? "auto" : "hidden"});
+            });
+        }
+    },
+
+    setOverflowY: function (b) {
+        var self = this;
+        if (this.options.overflowY !== !!b) {
+            this.options.overflowY = !!b;
+            BI.nextTick(function () {
+                self.element.css({overflowY: !!b ? "auto" : "hidden"});
+            });
+        }
+    },
+
+    getScrollLeft: function () {
+        return this.options.scrollLeft;
+    },
+
+    getScrollTop: function () {
+        return this.options.scrollTop;
+    },
+
+    getMaxScrollLeft: function () {
+        return this._getMaxScrollLeft();
+    },
+
+    getMaxScrollTop: function () {
+        return this._getMaxScrollTop();
+    },
+
+    restore: function () {
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+        this._scrollLock = false;
+    },
+
+    populate: function (items) {
+        if (items && items !== this.options.items) {
+            this.options.items = items;
+            this._calculateSizeAndPositionData();
+        }
+        this._populate();
+    }
+});
+BI.Collection.EVENT_SCROLL = "EVENT_SCROLL";
+$.shortcut('bi.collection_view', BI.Collection);/**
+ * @class BI.Combo
+ * @extends BI.Widget
+ */
+BI.Combo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Combo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-combo",
+            trigger: "click",
+            toggle: true,
+            direction: "bottom", //top||bottom||left||right||top,left||top,right||bottom,left||bottom,right
+            isDefaultInit: false,
+            isNeedAdjustHeight: true,//是否需要高度调整
+            isNeedAdjustWidth: true,
+            adjustLength: 0,//调整的距离
+            adjustXOffset: 0,
+            adjustYOffset: 0,
+            hideChecker: BI.emptyFn,
+            offsetStyle: "left", //left,right,center
+            el: {},
+            popup: {},
+            comboClass: "bi-combo-popup",
+            hoverClass: "bi-combo-hover"
+        })
+    },
+
+    _init: function () {
+        BI.Combo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._initCombo();
+        this._initPullDownAction();
+        this.combo.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (self.isEnabled() && this.isEnabled()) {
+                if (type === BI.Events.EXPAND) {
+                    self._popupView();
+                }
+                if (type === BI.Events.COLLAPSE) {
+                    self._hideView();
+                }
+                if (type === BI.Events.EXPAND || type === BI.Events.COLLAPSE) {
+                    self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                }
+
+                if (type === BI.Events.CLICK) {
+                    self.fireEvent(BI.Combo.EVENT_TRIGGER_CHANGE, obj);
+                }
+            }
+        });
+
+        self.element.on("mouseenter." + self.getName(), function (e) {
+            if (self.isEnabled() && self.combo.isEnabled()) {
+                self.element.addClass(o.hoverClass);
+            }
+        });
+        self.element.on("mouseleave." + self.getName(), function (e) {
+            if (self.isEnabled() && self.combo.isEnabled()) {
+                self.element.removeClass(o.hoverClass);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [
+                {el: this.combo}
+            ]
+        });
+        o.isDefaultInit && (this._assertPopupView());
+        BI.Resizers.add(this.getName(), BI.bind(function () {
+            if (this.isViewVisible()) {
+                this._hideView();
+            }
+        }, this));
+    },
+
+    _toggle: function () {
+        this._assertPopupViewRender();
+        if (this.popupView.isVisible()) {
+            this._hideView();
+        } else {
+            if (this.isEnabled()) {
+                this._popupView();
+            }
+        }
+    },
+
+    _initPullDownAction: function () {
+        var self = this, o = this.options;
+        var evs = this.options.trigger.split(",");
+        BI.each(evs, function (i, ev) {
+            switch (ev) {
+                case "hover":
+                    self.element.on("mouseenter." + self.getName(), function (e) {
+                        if (self.isEnabled() && self.combo.isEnabled()) {
+                            self._popupView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.combo);
+                            self.fireEvent(BI.Combo.EVENT_EXPAND);
+                        }
+                    });
+                    self.element.on("mouseleave." + self.getName(), function (e) {
+                        if (self.isEnabled() && self.combo.isEnabled() && o.toggle === true) {
+                            self._hideView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", self.combo);
+                            self.fireEvent(BI.Combo.EVENT_COLLAPSE);
+                        }
+                    });
+                    break;
+                case "click":
+                    if (ev) {
+                        self.element.off(ev + "." + self.getName()).on(ev + "." + self.getName(), BI.debounce(function (e) {
+                            if (self.combo.element.__isMouseInBounds__(e)) {
+                                if (self.isEnabled() && self.combo.isEnabled()) {
+                                    o.toggle ? self._toggle() : self._popupView();
+                                    if (self.isViewVisible()) {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.combo);
+                                        self.fireEvent(BI.Combo.EVENT_EXPAND);
+                                    } else {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", self.combo);
+                                        self.fireEvent(BI.Combo.EVENT_COLLAPSE);
+                                    }
+                                }
+                            }
+                        }, BI.EVENT_RESPONSE_TIME, true));
+                    }
+                    break;
+            }
+        })
+    },
+
+    _initCombo: function () {
+        this.combo = BI.createWidget(this.options.el);
+    },
+
+    _assertPopupView: function () {
+        var self = this;
+        if (this.popupView == null) {
+            this.popupView = BI.createWidget(this.options.popup, {
+                type: "bi.popup_view"
+            });
+            this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    self.combo.setValue(self.getValue());
+                    self.fireEvent(BI.Combo.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            this.popupView.setVisible(false);
+            BI.nextTick(function () {
+                self.fireEvent(BI.Combo.EVENT_AFTER_INIT);
+            });
+        }
+    },
+
+    _assertPopupViewRender: function () {
+        this._assertPopupView();
+        if (!this._rendered) {
+            BI.createWidget({
+                type: "bi.vertical",
+                scrolly: false,
+                element: this,
+                items: [
+                    {el: this.popupView}
+                ]
+            });
+            this._rendered = true;
+        }
+    },
+
+    _hideIf: function (e) {
+        if (this.element.__isMouseInBounds__(e) || (this.popupView && this.popupView.element.__isMouseInBounds__(e))) {
+            return;
+        }
+        if (this.element.find(e.target).length > 0) {
+            return;
+        }
+        var isHide = this.options.hideChecker.apply(this, [e]);
+        if (isHide === false) {
+            return;
+        }
+        this._hideView();
+    },
+
+    _hideView: function () {
+        this.fireEvent(BI.Combo.EVENT_BEFORE_HIDEVIEW);
+        this.popupView && this.popupView.invisible();
+        this.element.removeClass(this.options.comboClass);
+
+        $(document).unbind("mousedown." + this.getName()).unbind("mousewheel." + this.getName());
+        this.fireEvent(BI.Combo.EVENT_AFTER_HIDEVIEW);
+    },
+
+    _popupView: function () {
+        this._assertPopupViewRender();
+        this.fireEvent(BI.Combo.EVENT_BEFORE_POPUPVIEW);
+
+        this.popupView.visible();
+        this.adjustWidth();
+        this.adjustHeight();
+
+        this.element.addClass(this.options.comboClass);
+        $(document).bind("mousedown." + this.getName(), BI.bind(this._hideIf, this)).bind("mousewheel." + this.getName(), BI.bind(this._hideIf, this));
+        this.fireEvent(BI.Combo.EVENT_AFTER_POPUPVIEW);
+    },
+
+    adjustWidth: function () {
+        var o = this.options;
+        if (!this.popupView) {
+            return;
+        }
+        if (o.isNeedAdjustWidth === true) {
+            this.resetListWidth("");
+            var width = this.popupView.element.outerWidth();
+            var maxW = this.element.outerWidth() || o.width;
+            if (width > maxW + 80) {
+                maxW = maxW + 80;
+            } else if (width > maxW) {
+                maxW = width;
+            }
+            this.resetListWidth(maxW < 100 ? 100 : maxW);
+        }
+    },
+
+    adjustHeight: function () {
+        var o = this.options, p = {};
+        if (!this.popupView) {
+            return;
+        }
+        var isVisible = this.popupView.isVisible();
+        this.popupView.visible();
+        switch (o.direction) {
+            case "bottom":
+            case "bottom,right":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['bottom', 'top', 'right', 'left'], o.offsetStyle);
+                break;
+            case "top":
+            case "top,right":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['top', 'bottom', 'right', 'left'], o.offsetStyle);
+                break;
+            case "left":
+            case "left,bottom":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['left', 'right', 'bottom', 'top'], o.offsetStyle);
+                break;
+            case "right":
+            case "right,bottom":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['right', 'left', 'bottom', 'top'], o.offsetStyle);
+                break;
+            case "top,left":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['top', 'bottom', 'left', 'right'], o.offsetStyle);
+                break;
+            case "bottom,left":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['bottom', 'top', 'left', 'right'], o.offsetStyle);
+                break;
+            case "left,top":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['left', 'right', 'top', 'bottom'], o.offsetStyle);
+                break;
+            case "right,top":
+                p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['right', 'left', 'top', 'bottom'], o.offsetStyle);
+                break;
+            case "top,custom":
+            case "custom,top":
+                p = $.getTopAdaptPosition(this.combo, this.popupView, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight);
+                break;
+            case "custom,bottom":
+            case "bottom,custom":
+                p = $.getBottomAdaptPosition(this.combo, this.popupView, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight);
+                break;
+            case "left,custom":
+            case "custom,left":
+                p = $.getLeftAdaptPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength);
+                delete p.top;
+                delete p.adaptHeight;
+                break;
+            case "custom,right":
+            case "right,custom":
+                p = $.getRightAdaptPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength);
+                delete p.top;
+                delete p.adaptHeight;
+                break;
+        }
+
+        if ("adaptHeight" in p) {
+            this.resetListHeight(p['adaptHeight']);
+        }
+        if ("left" in p) {
+            this.popupView.element.css({
+                left: p.left
+            });
+        }
+        if ("top" in p) {
+            this.popupView.element.css({
+                top: p.top
+            });
+        }
+        this.popupView.setVisible(isVisible);
+    },
+
+    resetListHeight: function (h) {
+        this._assertPopupView();
+        this.popupView.resetHeight && this.popupView.resetHeight(h);
+    },
+
+    resetListWidth: function (w) {
+        this._assertPopupView();
+        this.popupView.resetWidth && this.popupView.resetWidth(w);
+    },
+
+    populate: function (items) {
+        this._assertPopupView();
+        this.popupView.populate.apply(this.popupView, arguments);
+        this.combo.populate.apply(this.combo, arguments);
+    },
+
+    setEnable: function (arg) {
+        BI.Combo.superclass.setEnable.apply(this, arguments);
+        this.combo && this.combo.setEnable(arg);
+        this.popupView && this.popupView.setEnable(arg);
+        !arg && this._hideView();
+    },
+
+    setValue: function (v) {
+        this._assertPopupView();
+        this.combo.setValue(v);
+        this.popupView && this.popupView.setValue(v);
+    },
+
+    getValue: function () {
+        this._assertPopupView();
+        return this.popupView && this.popupView.getValue();
+    },
+
+    isViewVisible: function () {
+        return this.isEnabled() && this.combo.isEnabled() && !!this.popupView && this.popupView.isVisible();
+    },
+
+    showView: function () {
+        if (this.isEnabled() && this.combo.isEnabled()) {
+            this._popupView();
+        }
+    },
+
+    hideView: function () {
+        this._hideView();
+    },
+
+    getView: function () {
+        return this.popupView;
+    },
+
+    doBehavior: function () {
+        this._assertPopupView();
+        this.popupView && this.popupView.doBehavior.apply(this.popupView, arguments);
+    },
+
+    toggle: function () {
+        this._toggle();
+    },
+
+    destroyed: function () {
+        $(document).unbind("mousedown." + this.getName())
+            .unbind("mousewheel." + this.getName())
+            .unbind("mouseenter." + this.getName())
+            .unbind("mousemove." + this.getName())
+            .unbind("mouseleave." + this.getName());
+        this.popupView && this.popupView.destroy();
+        BI.Resizers.remove(this.getName());
+    }
+});
+BI.Combo.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE";
+BI.Combo.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Combo.EVENT_EXPAND = "EVENT_EXPAND";
+BI.Combo.EVENT_COLLAPSE = "EVENT_COLLAPSE";
+BI.Combo.EVENT_AFTER_INIT = "EVENT_AFTER_INIT";
+
+
+BI.Combo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.Combo.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW";
+BI.Combo.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW";
+BI.Combo.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW";
+
+$.shortcut("bi.combo", BI.Combo);/**
+ *
+ * 某个可以展开的节点
+ *
+ * Created by GUY on 2015/9/10.
+ * @class BI.Expander
+ * @extends BI.Widget
+ */
+BI.Expander = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Expander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-expander",
+            trigger: "click",
+            toggle: true,
+            //direction: "bottom", //top,bottom四个方向
+            isDefaultInit: false, //是否默认初始化子节点
+            el: {},
+            popup: {},
+            expanderClass: "bi-expander-popup",
+            hoverClass: "bi-expander-hover"
+        })
+    },
+
+    _init: function () {
+        BI.Expander.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._expanded = !!o.el.open;
+        this._initExpander();
+        this._initPullDownAction();
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (type === BI.Events.EXPAND) {
+                self._popupView();
+            }
+            if (type === BI.Events.COLLAPSE) {
+                self._hideView();
+            }
+            if (self.isEnabled() && this.isEnabled()) {
+                if (type === BI.Events.EXPAND || type === BI.Events.COLLAPSE) {
+                    self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                }
+                if (type === BI.Events.CLICK) {
+                    self.fireEvent(BI.Expander.EVENT_TRIGGER_CHANGE, value, obj);
+                }
+            }
+        });
+
+        this.element.hover(function () {
+            if (self.isEnabled() && self.expander.isEnabled()) {
+                self.element.addClass(o.hoverClass);
+            }
+        }, function () {
+            if (self.isEnabled() && self.expander.isEnabled()) {
+                self.element.removeClass(o.hoverClass);
+            }
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [
+                {el: this.expander}
+            ]
+        });
+        o.isDefaultInit && this._assertPopupView();
+        if (this.expander.isOpened() === true) {
+            this._popupView();
+        }
+    },
+
+    _toggle: function () {
+        this._assertPopupViewRender();
+        if (this.popupView.isVisible()) {
+            this._hideView();
+        } else {
+            if (this.isEnabled()) {
+                this._popupView();
+            }
+        }
+    },
+
+    _initPullDownAction: function () {
+        var self = this, o = this.options;
+        var evs = this.options.trigger.split(",");
+        BI.each(evs, function (i, e) {
+            switch (e) {
+                case "hover":
+                    self.element[e](function (e) {
+                        if (self.isEnabled() && self.expander.isEnabled()) {
+                            self._popupView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.expander);
+                            self.fireEvent(BI.Expander.EVENT_EXPAND);
+                        }
+                    }, function () {
+                        if (self.isEnabled() && self.expander.isEnabled() && o.toggle) {
+                            self._hideView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.expander);
+                            self.fireEvent(BI.Expander.EVENT_COLLAPSE);
+                        }
+                    });
+                    break;
+                default :
+                    if (e) {
+                        self.element.off(e + "." + self.getName()).on(e + "." + self.getName(), BI.debounce(function (e) {
+                            if (self.expander.element.__isMouseInBounds__(e)) {
+                                if (self.isEnabled() && self.expander.isEnabled()) {
+                                    o.toggle ? self._toggle() : self._popupView();
+                                    if (self.isExpanded()) {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.expander);
+                                        self.fireEvent(BI.Expander.EVENT_EXPAND);
+                                    } else {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.expander);
+                                        self.fireEvent(BI.Expander.EVENT_COLLAPSE);
+                                    }
+                                }
+                            }
+                        }, BI.EVENT_RESPONSE_TIME, true));
+                    }
+                    break;
+            }
+        })
+    },
+
+    _initExpander: function () {
+        this.expander = BI.createWidget(this.options.el);
+    },
+
+    _assertPopupView: function () {
+        var self = this;
+        if (this.popupView == null) {
+            this.popupView = BI.createWidget(this.options.popup, {
+                type: "bi.button_group",
+                cls: "expander-popup",
+                layouts: [{
+                    type: "bi.vertical",
+                    hgap: 0,
+                    vgap: 0
+                }]
+            });
+            this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                if (type === BI.Events.CLICK) {
+                    //self.setValue(self.getValue());
+                    self.fireEvent(BI.Expander.EVENT_CHANGE, value, obj);
+                }
+            });
+            this.popupView.setVisible(this.isExpanded());
+            BI.nextTick(function () {
+                self.fireEvent(BI.Expander.EVENT_AFTER_INIT);
+            });
+        }
+    },
+
+    _assertPopupViewRender: function () {
+        this._assertPopupView();
+        if (!this._rendered) {
+            BI.createWidget({
+                type: "bi.vertical",
+                scrolly: false,
+                element: this,
+                items: [
+                    {el: this.popupView}
+                ]
+            });
+            this._rendered = true;
+        }
+    },
+
+    _hideView: function () {
+        this.fireEvent(BI.Expander.EVENT_BEFORE_HIDEVIEW);
+        this._expanded = false;
+        this.expander.setOpened(false);
+        this.popupView && this.popupView.invisible();
+        this.element.removeClass(this.options.expanderClass);
+
+        this.fireEvent(BI.Expander.EVENT_AFTER_HIDEVIEW);
+    },
+
+    _popupView: function () {
+        this._assertPopupViewRender();
+        this.fireEvent(BI.Expander.EVENT_BEFORE_POPUPVIEW);
+        this._expanded = true;
+        this.expander.setOpened(true);
+        this.popupView.visible();
+        this.element.addClass(this.options.expanderClass);
+        this.fireEvent(BI.Expander.EVENT_AFTER_POPUPVIEW);
+    },
+
+    populate: function (items) {
+        //this._assertPopupView();
+        this.popupView && this.popupView.populate.apply(this.popupView, arguments);
+        this.expander.populate.apply(this.expander, arguments);
+    },
+
+    setEnable: function (arg) {
+        BI.Expander.superclass.setEnable.apply(this, arguments);
+        this.expander && this.expander.setEnable(arg);
+        this.popupView && this.popupView.setEnable(arg);
+        !arg && this._hideView();
+    },
+
+    setValue: function (v) {
+        //this._assertPopupView();
+        this.expander.setValue(v);
+        this.popupView && this.popupView.setValue(v);
+    },
+
+    getValue: function () {
+        //this._assertPopupView();
+        return this.popupView ? this.popupView.getValue() : [];
+    },
+
+    isViewVisible: function () {
+        return this.isEnabled() && this.expander.isEnabled() && !!this.popupView && this.popupView.isVisible();
+    },
+
+    isExpanded: function () {
+        return this._expanded;
+    },
+
+    showView: function () {
+        if (this.isEnabled() && this.expander.isEnabled()) {
+            this._popupView();
+        }
+    },
+
+    hideView: function () {
+        this._hideView();
+    },
+
+    getView: function () {
+        return this.popupView;
+    },
+
+    doBehavior: function () {
+        //this._assertPopupView();
+        this.popupView && this.popupView.doBehavior.apply(this.popupView, arguments);
+    },
+
+    getAllLeaves: function () {
+        return this.popupView && this.popupView.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        if (this.expander.options.id === id) {
+            return this.expander;
+        }
+        return this.popupView && this.popupView.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        if (this.expander.getValue() === value) {
+            return this.expander;
+        }
+        return this.popupView && this.popupView.getNodeByValue(value);
+    },
+
+    destroyed: function () {
+        this.popupView && this.popupView.destroy();
+    }
+});
+BI.Expander.EVENT_EXPAND = "EVENT_EXPAND";
+BI.Expander.EVENT_COLLAPSE = "EVENT_COLLAPSE";
+BI.Expander.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE";
+BI.Expander.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Expander.EVENT_AFTER_INIT = "EVENT_AFTER_INIT";
+
+
+BI.Expander.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.Expander.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW";
+BI.Expander.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW";
+BI.Expander.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW";
+
+$.shortcut("bi.expander", BI.Expander);/**
+ * Created by GUY on 2015/6/26.
+ * @class BI.ButtonGroup
+ * @extends BI.Widget
+ */
+
+BI.ButtonGroup = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ButtonGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-button-group",
+            behaviors: {},
+            items: [
+                {
+                    el: {type: "bi.text_button", text: "", value: ""}
+                }
+            ],
+            chooseType: BI.Selection.Single,
+            layouts: [{
+                type: "bi.center",
+                hgap: 0,
+                vgap: 0
+            }]
+        })
+    },
+
+    _init: function () {
+        BI.ButtonGroup.superclass._init.apply(this, arguments);
+        var behaviors = {};
+        BI.each(this.options.behaviors, function (key, rule) {
+            behaviors[key] = BI.BehaviorFactory.createBehavior(key, {
+                rule: rule
+            })
+        });
+        this.behaviors = behaviors;
+        this.populate(this.options.items);
+    },
+
+    _createBtns: function (items) {
+        var o = this.options;
+        return BI.createWidgets(BI.createItems(items, {
+            type: "bi.text_button"
+        }));
+    },
+
+    _btnsCreator: function (items) {
+        var self = this, args = Array.prototype.slice.call(arguments), o = this.options;
+        var buttons = this._createBtns(items);
+        args[0] = buttons;
+
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    switch (o.chooseType) {
+                        case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                            self.setValue(btn.getValue());
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_NONE:
+                            self.setValue([]);
+                            break;
+                    }
+                    self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            btn.on(BI.Events.DESTROY, function () {
+                BI.remove(self.buttons, btn);
+            })
+        });
+
+        return buttons;
+    },
+
+    _packageBtns: function (btns) {
+        var o = this.options;
+
+        for (var i = o.layouts.length - 1; i > 0; i--) {
+            btns = BI.map(btns, function (k, it) {
+                return BI.extend({}, o.layouts[i], {
+                    items: [
+                        BI.extend({}, o.layouts[i].el, {
+                            el: it
+                        })
+                    ]
+                })
+            })
+        }
+        return btns;
+    },
+
+    _packageItems: function (items, packBtns) {
+        return BI.createItems(BI.makeArrayByArray(items, {}), BI.clone(packBtns));
+    },
+
+    _packageLayout: function (items) {
+        var o = this.options, layout = BI.deepClone(o.layouts[0]);
+
+        var lay = BI.formatEL(layout).el;
+        while (lay && lay.items && !BI.isEmpty(lay.items)) {
+            lay = BI.formatEL(lay.items[0]).el;
+        }
+        lay.items = items;
+        return layout;
+    },
+
+
+    doBehavior: function () {
+        var args = Array.prototype.slice.call(arguments);
+        args.unshift(this.buttons);
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        })
+    },
+
+    prependItems: function (items) {
+        var o = this.options;
+        var btns = this._btnsCreator.apply(this, arguments);
+        this.buttons = BI.concat(btns, this.buttons);
+
+        //如果是一个简单的layout
+        if (o.layouts.length === 1 && !BI.isNotEmptyArray(o.layouts[0].items)
+            && this.layouts && this.layouts.prependItems) {
+            this.layouts.prependItems(btns);
+            return;
+        }
+
+        var items = this._packageItems(items, this._packageBtns(btns));
+        BI.createWidget(BI.extend(this._packageLayout(items))).element.children().prependTo(this.element);
+    },
+
+    addItems: function (items) {
+        var o = this.options;
+        var btns = this._btnsCreator.apply(this, arguments);
+        this.buttons = BI.concat(this.buttons, btns);
+
+        //如果是一个简单的layout
+        if (o.layouts.length === 1 && !BI.isNotEmptyArray(o.layouts[0].items)
+            && this.layouts && this.layouts.addItems) {
+            this.layouts.addItems(btns);
+            return;
+        }
+
+        var items = this._packageItems(items, this._packageBtns(btns));
+        BI.createWidget(BI.extend(this._packageLayout(items))).element.children().appendTo(this.element);
+    },
+
+    removeItemAt: function (indexes) {
+        var self = this;
+        indexes = BI.isArray(indexes) ? indexes : [indexes];
+        var buttons = [];
+        BI.each(indexes, function (i, index) {
+            buttons.push(self.buttons[index]);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn && btn.destroy();
+        })
+    },
+
+    removeItems: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        var indexes = [];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                indexes.push(i);
+            }
+        });
+        this.removeItemAt(indexes);
+    },
+
+    populate: function (items) {
+        this.options.items = items || [];
+        this.empty();
+
+        this.buttons = this._btnsCreator.apply(this, arguments);
+        var items = this._packageItems(items, this._packageBtns(this.buttons));
+
+        this.layouts = BI.createWidget(BI.extend({element: this}, this._packageLayout(items)));
+    },
+
+    setEnable: function (b) {
+        BI.ButtonGroup.superclass.setEnable.apply(this, arguments);
+        BI.each(this.buttons, function (i, item) {
+            item.setEnable(b);
+        });
+    },
+
+    setNotSelectedValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected && item.setSelected(false);
+            } else {
+                item.setSelected && item.setSelected(true);
+            }
+        });
+    },
+
+    setEnabledValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                item.setEnable(true);
+            } else {
+                item.setEnable(false);
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected && item.setSelected(true);
+            } else {
+                item.setSelected && item.setSelected(false);
+            }
+        });
+    },
+
+    getNotSelectedValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !(item.isSelected && item.isSelected())) {
+                v.push(item.getValue());
+            }
+        });
+        return v;
+    },
+
+    getValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.isSelected && item.isSelected()) {
+                v.push(item.getValue());
+            }
+        });
+        return v;
+    },
+
+    getAllButtons: function () {
+        return this.buttons;
+    },
+
+    getAllLeaves: function () {
+        return this.buttons;
+    },
+
+    getSelectedButtons: function () {
+        var btns = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isSelected && item.isSelected()) {
+                btns.push(item);
+            }
+        });
+        return btns;
+    },
+
+    getNotSelectedButtons: function () {
+        var btns = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isSelected && !item.isSelected()) {
+                btns.push(item);
+            }
+        });
+        return btns;
+    },
+
+    getIndexByValue: function (value) {
+        var index = -1;
+        BI.any(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.getValue() === value) {
+                index = i;
+                return true;
+            }
+        });
+        return index;
+    },
+
+    getNodeById: function (id) {
+        var node;
+        BI.any(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.options.id === id) {
+                node = item;
+                return true;
+            }
+        });
+        return node;
+    },
+
+    getNodeByValue: function (value) {
+        var node;
+        BI.any(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.getValue() === value) {
+                node = item;
+                return true;
+            }
+        });
+        return node;
+    }
+});
+BI.extend(BI.ButtonGroup, {
+    CHOOSE_TYPE_SINGLE: BI.Selection.Single,
+    CHOOSE_TYPE_MULTI: BI.Selection.Multi,
+    CHOOSE_TYPE_ALL: BI.Selection.All,
+    CHOOSE_TYPE_NONE: BI.Selection.None,
+    CHOOSE_TYPE_DEFAULT: BI.Selection.Default
+});
+BI.ButtonGroup.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.button_group", BI.ButtonGroup);
+/**
+ * Created by GUY on 2015/8/10.
+ */
+
+BI.ComboGroup = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ComboGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-combo-group",
+
+            //以下这些属性对每一个combo都是公用的
+            trigger: "click,hover",
+            direction: "right",
+            adjustLength: 0,
+            isDefaultInit: false,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+
+            el: {type: "bi.text_button", text: "", value: ""},
+            children: [],
+
+            popup: {
+                el: {
+                    type: "bi.button_tree",
+                    chooseType: 0,
+                    layouts: [{
+                        type: "bi.vertical"
+                    }]
+                }
+            }
+        })
+    },
+
+    _init: function () {
+        BI.ComboGroup.superclass._init.apply(this, arguments);
+        this.populate(this.options.el);
+    },
+
+    populate: function (item) {
+        var self = this, o = this.options;
+        var children = o.children;
+        if (BI.isEmpty(children)) {
+            throw new Error("ComboGroup构造错误");
+        }
+        BI.each(children, function (i, ch) {
+            var son = BI.formatEL(ch).el.children;
+            ch = BI.formatEL(ch).el;
+            if (!BI.isEmpty(son)) {
+                ch.el = BI.clone(ch);
+                ch.children = son;
+                ch.type = "bi.combo_group";
+                ch.action = o.action;
+                ch.height = o.height;
+                ch.direction = o.direction;
+                ch.isDefaultInit = o.isDefaultInit;
+                ch.isNeedAdjustHeight = o.isNeedAdjustHeight;
+                ch.isNeedAdjustWidth = o.isNeedAdjustWidth;
+                ch.adjustLength = o.adjustLength;
+                ch.popup = o.popup;
+            }
+        })
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            height: o.height,
+            trigger: o.trigger,
+            direction: o.direction,
+            isDefaultInit: o.isDefaultInit,
+            isNeedAdjustWidth: o.isNeedAdjustWidth,
+            isNeedAdjustHeight: o.isNeedAdjustHeight,
+            adjustLength: o.adjustLength,
+            el: item,
+            popup: BI.extend({}, o.popup, {
+                el: BI.extend({
+                    items: children
+                }, o.popup.el)
+            })
+        })
+        this.combo.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.ComboGroup.EVENT_CHANGE, obj);
+            }
+        })
+    },
+
+    setEnable: function (b) {
+        BI.ComboGroup.superclass.setEnable.apply(this, arguments);
+        this.combo && this.combo.setEnable(b);
+    },
+
+    getValue: function () {
+        return this.combo.getValue();
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    }
+});
+BI.ComboGroup.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.combo_group", BI.ComboGroup);/**
+ * 加载控件
+ *
+ * Created by GUY on 2015/8/31.
+ * @class BI.Loader
+ * @extends BI.Widget
+ */
+BI.Loader = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Loader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-loader",
+
+            direction: "top",
+            isDefaultInit: true,//是否默认初始化数据
+            logic: {
+                dynamic: true,
+                scrolly: true
+            },
+
+            //下面是button_group的属性
+            el: {
+                type: "bi.button_group"
+            },
+
+            items: [],
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn,
+
+            //下面是分页信息
+            count: false,
+            prev: false,
+            next: {},
+            hasPrev: BI.emptyFn,
+            hasNext: BI.emptyFn
+        })
+    },
+
+    _prevLoad: function () {
+        var self = this, o = this.options;
+        this.prev.setLoading();
+        o.itemsCreator.apply(this, [{times: --this.times}, function () {
+            self.prev.setLoaded();
+            self.prependItems.apply(self, arguments);
+        }]);
+    },
+
+    _nextLoad: function () {
+        var self = this, o = this.options;
+        this.next.setLoading();
+        o.itemsCreator.apply(this, [{times: ++this.times}, function () {
+            self.next.setLoaded();
+            self.addItems.apply(self, arguments);
+        }]);
+    },
+
+    _init: function () {
+        BI.Loader.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (o.itemsCreator === false) {
+            o.prev = false;
+            o.next = false;
+        }
+        if (o.prev !== false) {
+            this.prev = BI.createWidget(BI.extend({
+                type: "bi.loading_bar"
+            }, o.prev));
+            this.prev.on(BI.Controller.EVENT_CHANGE, function (type) {
+                if (type === BI.Events.CLICK) {
+                    self._prevLoad();
+                }
+            });
+        }
+
+        this.button_group = BI.createWidget(o.el, {
+            type: "bi.button_group",
+            chooseType: 0,
+            items: o.items,
+            behaviors: {},
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.Loader.EVENT_CHANGE, obj);
+            }
+        });
+
+        if (o.next !== false) {
+            this.next = BI.createWidget(BI.extend({
+                type: "bi.loading_bar"
+            }, o.next));
+            this.next.on(BI.Controller.EVENT_CHANGE, function (type) {
+                if (type === BI.Events.CLICK) {
+                    self._nextLoad();
+                }
+            })
+        }
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({
+            scrolly: true
+        }, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.prev, this.button_group, this.next)
+        }))));
+
+        o.isDefaultInit && BI.isEmpty(o.items) && BI.nextTick(BI.bind(function () {
+            o.isDefaultInit && BI.isEmpty(o.items) && this.populate();
+        }, this));
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+    },
+
+    hasPrev: function () {
+        var o = this.options;
+        if (BI.isNumber(o.count)) {
+            return this.count < o.count;
+        }
+        return !!o.hasPrev.apply(this, [{
+            times: this.times,
+            count: this.count
+        }])
+    },
+
+    hasNext: function () {
+        var o = this.options;
+        if (BI.isNumber(o.count)) {
+            return this.count < o.count;
+        }
+        return !!o.hasNext.apply(this, [{
+            times: this.times,
+            count: this.count
+        }])
+    },
+
+    prependItems: function (items) {
+        this.count += items.length;
+        if (this.next !== false) {
+            if (this.hasPrev()) {
+                this.options.items = this.options.items.concat(items);
+                this.prev.setLoaded();
+            } else {
+                this.prev.setEnd();
+            }
+        }
+        this.button_group.prependItems.apply(this.button_group, arguments);
+    },
+
+    addItems: function (items) {
+        this.count += items.length;
+        if (BI.isObject(this.next)) {
+            if (this.hasNext()) {
+                this.options.items = this.options.items.concat(items);
+                this.next.setLoaded();
+            } else {
+                this.next.setEnd();
+            }
+        }
+        this.button_group.addItems.apply(this.button_group, arguments);
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options;
+        if (arguments.length === 0 && (BI.isFunction(o.itemsCreator))) {
+            o.itemsCreator.apply(this, [{times: 1}, function () {
+                if (arguments.length === 0) {
+                    throw new Error("arguments can not be null!!!");
+                }
+                self.populate.apply(self, arguments);
+                o.onLoaded();
+            }]);
+            return;
+        }
+        this.options.items = items;
+        this.times = 1;
+        this.count = 0;
+        this.count += items.length;
+        if (BI.isObject(this.next)) {
+            if (this.hasNext()) {
+                this.next.setLoaded();
+            } else {
+                this.next.invisible();
+            }
+        }
+        if (BI.isObject(this.prev)) {
+            if (this.hasPrev()) {
+                this.prev.setLoaded();
+            } else {
+                this.prev.invisible();
+            }
+        }
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    setEnable: function (v) {
+        this.button_group.setEnable(v);
+    },
+
+    doBehavior: function () {
+        this.button_group.doBehavior.apply(this.button_group, arguments);
+    },
+
+    setNotSelectedValue: function () {
+        this.button_group.setNotSelectedValue.apply(this.button_group, arguments);
+    },
+
+    getNotSelectedValue: function () {
+        return this.button_group.getNotSelectedValue();
+    },
+
+    setValue: function () {
+        this.button_group.setValue.apply(this.button_group, arguments);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue.apply(this.button_group, arguments);
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.button_group.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.button_group.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.button_group.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.button_group.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.button_group.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.button_group.getNodeByValue(value);
+    },
+
+    empty: function () {
+        this.button_group.empty();
+        BI.each([this.prev, this.next], function (i, ob) {
+            ob && ob.setVisible(false);
+        });
+    }
+});
+BI.Loader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.loader", BI.Loader);/**
+ * Created by GUY on 2015/6/26.
+ */
+
+BI.Navigation = BI.inherit(BI.Widget, {
+    _defaultConfig: function(){
+        return BI.extend(BI.Navigation.superclass._defaultConfig.apply(this,arguments), {
+            direction: "bottom",//top, bottom, left, right, custom
+            logic: {
+                dynamic: false
+            },
+            defaultShowIndex: 0,
+            tab: {
+                type: "bi.button_group",
+                items: [],
+                layouts: []
+            },
+            cardCreator: function(v){
+                return BI.createWidget();
+            },
+
+            afterCardCreated: BI.emptyFn,
+            afterCardShow: BI.emptyFn
+        })
+    },
+
+    _init: function(){
+        BI.Navigation.superclass._init.apply(this,arguments);
+        var self = this, o = this.options;
+        this.tab = BI.createWidget(this.options.tab, {type: "bi.button_group"});
+        this.cardMap = {};
+        this.showIndex = 0;
+        this.layout = BI.createWidget({
+            type: "bi.card"
+        });
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout)
+        }))));
+
+
+        new BI.ShowListener({
+            eventObj: this.tab,
+            cardLayout: this.layout,
+            cardNameCreator: function(v){
+                return self.showIndex + v;
+            },
+            cardCreator: function(v){
+                var card = o.cardCreator(v);
+                self.cardMap[v] = card;
+                return card;
+            },
+            afterCardCreated: BI.bind(this.afterCardCreated, this),
+            afterCardShow: BI.bind(this.afterCardShow, this)
+        })
+        if(o.defaultShowIndex !== false){
+            this.setSelect(o.defaultShowIndex);
+        }
+    },
+
+    afterCardCreated: function(v){
+        var self = this;
+        this.cardMap[v].on(BI.Controller.EVENT_CHANGE, function(type, value, obj){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if(type ===  BI.Events.CLICK) {
+                self.fireEvent(BI.Navigation.EVENT_CHANGE, obj);
+            }
+        })
+        this.options.afterCardCreated.apply(this, arguments);
+    },
+
+    afterCardShow: function(v){
+        this.showIndex = v;
+        this.options.afterCardShow.apply(this, arguments);
+    },
+
+    populate: function(){
+        var card = this.layout.getShowingCard();
+        if(card){
+            return card.populate.apply(card, arguments);
+        }
+    },
+
+    setSelect: function(v){
+        this.showIndex = v;
+        if(!this.layout.isCardExisted(v)){
+            var card = this.options.cardCreator(v);
+            this.cardMap[v] = card;
+            this.layout.addCardByName(v, card);
+            this.afterCardCreated(v);
+        }
+        this.layout.showCardByName(v);
+        BI.nextTick(BI.bind(this.afterCardShow, this, v));
+    },
+
+    getSelect: function(){
+        return this.showIndex;
+    },
+
+    getSelectedCard: function(){
+        if(BI.isKey(this.showIndex)){
+            return this.cardMap[this.showIndex];
+        }
+    },
+
+    /**
+     * @override
+     */
+    setValue: function(v){
+        var card = this.layout.getShowingCard();
+        if(card){
+            card.setValue(v);
+        }
+    },
+
+    /**
+     * @override
+     */
+    getValue: function(){
+        var card = this.layout.getShowingCard();
+        if(card){
+            return card.getValue();
+        }
+    },
+
+    empty: function(){
+        this.layout.deleteAllCard();
+        this.cardMap = {};
+    }
+});
+BI.Navigation.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.navigation", BI.Navigation);/**
+ * 搜索逻辑控件
+ *
+ * Created by GUY on 2015/9/28.
+ * @class BI.Searcher
+ * @extends BI.Widget
+ */
+
+BI.Searcher = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Searcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-searcher",
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            vgap: 0,
+            hgap: 0,
+
+            isDefaultInit: false,
+            isAutoSearch: true, //是否自动搜索
+            isAutoSync: true, //是否自动同步数据, 即是否保持搜索面板和adapter面板状态值的统一
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+
+            //isAutoSearch为false时启用
+            onSearch: function (op, callback) {
+                callback([])
+            },
+
+
+            el: {
+                type: "bi.search_editor"
+            },
+
+            popup: {
+                type: "bi.searcher_view"
+            },
+
+            adapter: null,
+            masker: { //masker层
+                offset: {}
+            }
+        })
+    },
+
+    _init: function () {
+        BI.Searcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.editor = BI.createWidget(o.el, {
+            type: "bi.search_editor"
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            vgap: o.vgap,
+            hgap: o.hgap,
+            items: [this.editor]
+        });
+        o.isDefaultInit && (this._assertPopupView());
+
+        var search = BI.debounce(BI.bind(this._search, this), BI.EVENT_RESPONSE_TIME, true);
+        this.editor.on(BI.Controller.EVENT_CHANGE, function (type) {
+            switch (type) {
+                case BI.Events.STARTEDIT:
+                    self._startSearch();
+                    break;
+                case BI.Events.EMPTY:
+                    self._stopSearch();
+                    break;
+                case BI.Events.CHANGE:
+                    search();
+                    break;
+                case BI.Events.PAUSE:
+                    self._pauseSearch();
+                    break;
+            }
+        })
+    },
+
+    _assertPopupView: function () {
+        var self = this, o = this.options;
+        if (!BI.Maskers.has(this.getName())) {
+            this.popupView = BI.createWidget(o.popup, {
+                type: "bi.searcher_view",
+                chooseType: o.chooseType
+            });
+            BI.Maskers.create(this.getName(), o.adapter, {
+                offset: o.masker.offset,
+                container: this,
+                render: this.popupView
+            });
+
+            this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                if (type === BI.Events.CLICK) {
+                    if (o.isAutoSync) {
+                        var values = o.adapter.getValue();
+                        if (!obj.isSelected()) {
+                            o.adapter.setValue(BI.deepWithout(values, obj.getValue()));
+                        } else {
+                            switch (o.chooseType) {
+                                case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                                    o.adapter.setValue([obj.getValue()]);
+                                    break;
+                                case BI.ButtonGroup.CHOOSE_TYPE_MULTI:
+                                    values.push(obj.getValue());
+                                    o.adapter.setValue(values);
+                                    break;
+                            }
+                        }
+                    }
+                    self.fireEvent(BI.Searcher.EVENT_CHANGE, value, obj);
+                }
+            });
+            BI.nextTick(function () {
+                self.fireEvent(BI.Searcher.EVENT_AFTER_INIT);
+            });
+        }
+    },
+
+    _startSearch: function () {
+        this._assertPopupView();
+        this._stop = false;
+        this._isSearching = true;
+        this.fireEvent(BI.Searcher.EVENT_START);
+        this.popupView.startSearch && this.popupView.startSearch();
+        //搜索前先清空dom
+        BI.Maskers.get(this.getName()).empty();
+        BI.nextTick(function (name) {
+            BI.Maskers.show(name);
+        }, this.getName());
+    },
+
+    _pauseSearch: function () {
+        var o = this.options, name = this.getName();
+        this._stop = true;
+        BI.Maskers.hide(name);
+        if (BI.Maskers.has(name) && this._isSearching === true) {
+            this.popupView && this.popupView.pauseSearch && this.popupView.pauseSearch();
+            this.fireEvent(BI.Searcher.EVENT_PAUSE);
+        }
+        this._isSearching = false;
+    },
+
+    _stopSearch: function () {
+        var o = this.options, name = this.getName();
+        this._stop = true;
+        BI.Maskers.hide(name);
+        if (BI.Maskers.has(name) && this._isSearching === true) {
+            //搜索后清空dom
+            BI.nextTick(function () {
+                BI.Maskers.has(name) && BI.Maskers.get(name).empty();
+            });
+            this.popupView && this.popupView.stopSearch && this.popupView.stopSearch();
+            this.fireEvent(BI.Searcher.EVENT_STOP);
+        }
+        this._isSearching = false;
+    },
+
+    _search: function () {
+        var self = this, o = this.options, keyword = this.editor.getValue();
+        if (keyword === "" || this._stop) {
+            return;
+        }
+        if (o.isAutoSearch) {
+            var items = (o.adapter.getItems && o.adapter.getItems()) || o.adapter.attr("items") || [];
+            var finding = BI.Func.getSearchResult(items, keyword);
+            var matched = finding.matched, finded = finding.finded;
+            this.popupView.populate(finded, matched, keyword);
+            o.isAutoSync && this.popupView.setValue(o.adapter.getValue());
+            self.fireEvent(BI.Searcher.EVENT_SEARCHING);
+            return;
+        }
+        this.popupView.loading && this.popupView.loading();
+        o.onSearch({
+            times: 1,
+            keyword: keyword,
+            selectedValues: o.adapter.getValue()
+        }, function (searchResult, matchResult) {
+            if (!self._stop) {
+                var args = [].slice.call(arguments);
+                if (args.length > 0) {
+                    args.push(keyword);
+                }
+                BI.Maskers.show(self.getName());
+                self.popupView.populate.apply(self.popupView, args);
+                o.isAutoSync && self.popupView.setValue(o.adapter.getValue());
+                self.popupView.loaded && self.popupView.loaded();
+                self.fireEvent(BI.Searcher.EVENT_SEARCHING);
+            }
+        });
+    },
+
+    setAdapter: function (adapter) {
+        this.options.adapter = adapter;
+        BI.Maskers.remove(this.getName());
+    },
+
+    doSearch: function () {
+        if (this.isSearching()) {
+            this._search();
+        }
+    },
+
+    stopSearch: function () {
+        this._stopSearch();//先停止搜索,然后再去设置editor为空
+        //important:停止搜索必须退出编辑状态,这里必须加上try(input框不显示时blur会抛异常)
+        try {
+            this.editor.blur();
+        } catch (e) {
+            if (!this.editor.blur) {
+                throw new Error("editor没有实现blur方法");
+            }
+        } finally {
+            this.editor.setValue("");
+        }
+    },
+
+    isSearching: function () {
+        return this._isSearching;
+    },
+
+    isViewVisible: function () {
+        return this.editor.isEnabled() && BI.Maskers.isVisible(this.getName());
+    },
+
+    getView: function () {
+        return this.popupView;
+    },
+
+    hasMatched: function () {
+        this._assertPopupView();
+        return this.popupView.hasMatched();
+    },
+
+    adjustHeight: function () {
+        if (BI.Maskers.has(this.getName()) && BI.Maskers.get(this.getName()).isVisible()) {
+            BI.Maskers.show(this.getName());
+        }
+    },
+
+    adjustView: function () {
+        this.isViewVisible() && BI.Maskers.show(this.getName());
+    },
+
+    setValue: function (v) {
+        this._assertPopupView();
+        this.popupView && this.popupView.setValue(v);
+    },
+
+    getKeyword: function () {
+        return this.editor.getValue();
+    },
+
+    getValue: function () {
+        var o = this.options;
+        if (o.isAutoSync) {
+            return o.adapter.getValue();
+        }
+        if (this.isSearching()) {
+            return this.popupView.getValue();
+        } else {
+            return o.adapter.getValue();
+        }
+    },
+
+    populate: function (result, searchResult, keyword) {
+        var o = this.options;
+        this._assertPopupView();
+        this.popupView.populate.apply(this.popupView, arguments);
+        if (o.isAutoSync) {
+            this.popupView.setValue(o.adapter.getValue());
+        }
+    },
+
+    empty: function () {
+        this.popupView && this.popupView.empty();
+    },
+
+    destroyed: function () {
+        this.popupView && this.popupView.destroy();
+        BI.Maskers.remove(this.getName());
+    }
+});
+BI.Searcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Searcher.EVENT_START = "EVENT_START";
+BI.Searcher.EVENT_STOP = "EVENT_STOP";
+BI.Searcher.EVENT_PAUSE = "EVENT_PAUSE";
+BI.Searcher.EVENT_SEARCHING = "EVENT_SEARCHING";
+BI.Searcher.EVENT_AFTER_INIT = "EVENT_AFTER_INIT";
+
+$.shortcut("bi.searcher", BI.Searcher);/**
+ *
+ * 切换显示或隐藏面板
+ *
+ * Created by GUY on 2015/11/2.
+ * @class BI.Switcher
+ * @extends BI.Widget
+ */
+BI.Switcher = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Switcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-switcher",
+            direction: BI.Direction.Top,
+            trigger: "click",
+            toggle: true,
+            el: {},
+            popup: {},
+            adapter: null,
+            masker: {},
+            switcherClass: "bi-switcher-popup",
+            hoverClass: "bi-switcher-hover"
+        })
+    },
+
+    _init: function () {
+        BI.Switcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._initSwitcher();
+        this._initPullDownAction();
+        this.switcher.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (self.isEnabled() && this.isEnabled()) {
+                if (type === BI.Events.EXPAND) {
+                    self._popupView();
+                }
+                if (type === BI.Events.COLLAPSE) {
+                    self._hideView();
+                }
+                if (type === BI.Events.EXPAND || type === BI.Events.COLLAPSE) {
+                    self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                }
+                if (type === BI.Events.CLICK) {
+                    self.fireEvent(BI.Switcher.EVENT_TRIGGER_CHANGE, value, obj);
+                }
+            }
+        });
+
+        this.element.hover(function () {
+            if (self.isEnabled() && self.switcher.isEnabled()) {
+                self.element.addClass(o.hoverClass);
+            }
+        }, function () {
+            if (self.isEnabled() && self.switcher.isEnabled()) {
+                self.element.removeClass(o.hoverClass);
+            }
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [
+                {el: this.switcher}
+            ]
+        });
+        o.isDefaultInit && (this._assertPopupView());
+    },
+
+    _toggle: function () {
+        this._assertPopupView();
+        if (this.isExpanded()) {
+            this._hideView();
+        } else {
+            if (this.isEnabled()) {
+                this._popupView();
+            }
+        }
+    },
+
+    _initPullDownAction: function () {
+        var self = this, o = this.options;
+        var evs = this.options.trigger.split(",");
+        BI.each(evs, function (i, e) {
+            switch (e) {
+                case "hover":
+                    self.element[e](function (e) {
+                        if (self.isEnabled() && self.switcher.isEnabled()) {
+                            self._popupView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.switcher);
+                            self.fireEvent(BI.Switcher.EVENT_EXPAND);
+                        }
+                    }, function () {
+                        if (self.isEnabled() && self.switcher.isEnabled() && o.toggle) {
+                            self._hideView();
+                            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.switcher);
+                            self.fireEvent(BI.Switcher.EVENT_COLLAPSE);
+                        }
+                    });
+                    break;
+                default :
+                    if (e) {
+                        self.element.off(e + "." + self.getName()).on(e + "." + self.getName(), BI.debounce(function (e) {
+                            if (self.switcher.element.__isMouseInBounds__(e)) {
+                                if (self.isEnabled() && self.switcher.isEnabled()) {
+                                    o.toggle ? self._toggle() : self._popupView();
+                                    if (self.isExpanded()) {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.switcher);
+                                        self.fireEvent(BI.Switcher.EVENT_EXPAND);
+                                    } else {
+                                        self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.switcher);
+                                        self.fireEvent(BI.Switcher.EVENT_COLLAPSE);
+                                    }
+                                }
+                            }
+                        }, BI.EVENT_RESPONSE_TIME, true));
+                    }
+                    break;
+            }
+        })
+    },
+
+    _initSwitcher: function () {
+        this.switcher = BI.createWidget(this.options.el);
+    },
+
+    _assertPopupView: function () {
+        var self = this, o = this.options;
+        if (!this._created) {
+            this.popupView = BI.createWidget(o.popup, {
+                type: "bi.button_group",
+                element: o.adapter && BI.Maskers.create(this.getName(), o.adapter, BI.extend({container: this}, o.masker)),
+                cls: "switcher-popup",
+                layouts: [{
+                    type: "bi.vertical",
+                    hgap: 0,
+                    vgap: 0
+                }]
+            });
+            this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+                if (type === BI.Events.CLICK) {
+                    self.fireEvent(BI.Switcher.EVENT_CHANGE, value, obj);
+                }
+            });
+            if (o.direction !== BI.Direction.Custom && !o.adapter) {
+                BI.createWidget({
+                    type: "bi.vertical",
+                    scrolly: false,
+                    element: this,
+                    items: [
+                        {el: this.popupView}
+                    ]
+                });
+            }
+            this._created = true;
+            BI.nextTick(function () {
+                self.fireEvent(BI.Switcher.EVENT_AFTER_INIT);
+            });
+        }
+    },
+
+    _hideView: function () {
+        this.fireEvent(BI.Switcher.EVENT_BEFORE_HIDEVIEW);
+        var self = this, o = this.options;
+        o.adapter ? BI.Maskers.hide(self.getName()) : (self.popupView && self.popupView.setVisible(false));
+        BI.nextTick(function () {
+            o.adapter ? BI.Maskers.hide(self.getName()) : (self.popupView && self.popupView.setVisible(false));
+            self.element.removeClass(o.switcherClass);
+            self.fireEvent(BI.Switcher.EVENT_AFTER_HIDEVIEW);
+        });
+    },
+
+    _popupView: function () {
+        var self = this, o = this.options;
+        this._assertPopupView();
+        this.fireEvent(BI.Switcher.EVENT_BEFORE_POPUPVIEW);
+        o.adapter ? BI.Maskers.show(this.getName()) : self.popupView.setVisible(true);
+        BI.nextTick(function (name) {
+            o.adapter ? BI.Maskers.show(name) : self.popupView.setVisible(true);
+            self.element.addClass(o.switcherClass);
+            self.fireEvent(BI.Switcher.EVENT_AFTER_POPUPVIEW);
+        }, this.getName());
+    },
+
+    populate: function (items) {
+        this._assertPopupView();
+        this.popupView.populate.apply(this.popupView, arguments);
+        this.switcher.populate.apply(this.switcher, arguments);
+    },
+
+    setEnable: function (arg) {
+        BI.Switcher.superclass.setEnable.apply(this, arguments);
+        this.switcher && this.switcher.setEnable(arg);
+        this.popupView && this.popupView.setEnable(arg);
+        !arg && this._hideView();
+    },
+
+    setValue: function (v) {
+        this._assertPopupView();
+        this.switcher.setValue(v);
+        this.popupView && this.popupView.setValue(v);
+    },
+
+    getValue: function () {
+        this._assertPopupView();
+        return this.popupView ? this.popupView.getValue() : [];
+    },
+
+    isViewVisible: function () {
+        return this.isEnabled() && this.switcher.isEnabled() &&
+            (this.options.adapter ? BI.Maskers.isVisible(this.getName()) : (this.popupView && this.popupView.isVisible()));
+    },
+
+    isExpanded: function () {
+        return this.isViewVisible();
+    },
+
+    showView: function () {
+        if (this.isEnabled() && this.switcher.isEnabled()) {
+            this._popupView();
+        }
+    },
+
+    hideView: function () {
+        this._hideView();
+    },
+
+    getView: function () {
+        return this.popupView;
+    },
+
+    adjustView: function () {
+        this.isViewVisible() && BI.Maskers.show(this.getName());
+    },
+
+    doBehavior: function () {
+        this._assertPopupView();
+        this.popupView && this.popupView.doBehavior.apply(this.popupView, arguments);
+    },
+
+    getAllLeaves: function () {
+        return this.popupView && this.popupView.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        if (this.switcher.attr("id") === id) {
+            return this.switcher;
+        }
+        return this.popupView && this.popupView.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        if (this.switcher.getValue() === value) {
+            return this.switcher;
+        }
+        return this.popupView && this.popupView.getNodeByValue(value);
+    },
+
+    empty: function () {
+        this.popupView && this.popupView.empty();
+    },
+
+    destroyed: function () {
+        this.popupView && this.popupView.destroy();
+    }
+});
+BI.Switcher.EVENT_EXPAND = "EVENT_EXPAND";
+BI.Switcher.EVENT_COLLAPSE = "EVENT_COLLAPSE";
+BI.Switcher.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE";
+BI.Switcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Switcher.EVENT_AFTER_INIT = "EVENT_AFTER_INIT";
+
+
+BI.Switcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.Switcher.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW";
+BI.Switcher.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW";
+BI.Switcher.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW";
+
+$.shortcut("bi.switcher", BI.Switcher);/**
+ * Created by GUY on 2015/6/26.
+ */
+
+BI.Tab = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Tab.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tab",
+            direction: "top",//top, bottom, left, right, custom
+            logic: {
+                dynamic: false
+            },
+            defaultShowIndex: 0,
+            tab: false,
+            cardCreator: function (v) {
+                return BI.createWidget();
+            }
+        })
+    },
+
+    _init: function () {
+        BI.Tab.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isObject(o.tab)) {
+            this.tab = BI.createWidget(this.options.tab, {type: "bi.button_group"});
+            this.tab.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            })
+        }
+        this.cardMap = {};
+        this.layout = BI.createWidget({
+            type: "bi.card"
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout)
+        }))));
+
+        var listener = new BI.ShowListener({
+            eventObj: this.tab,
+            cardLayout: this.layout,
+            cardCreator: function (v) {
+                var card = o.cardCreator.apply(self, arguments);
+                self.cardMap[v] = card;
+                return card;
+            },
+            afterCardShow: function (v) {
+                self.curr = v;
+            }
+        });
+        listener.on(BI.ShowListener.EVENT_CHANGE, function (value) {
+            self.fireEvent(BI.Tab.EVENT_CHANGE, value, self);
+        });
+        if (o.defaultShowIndex !== false) {
+            this.setSelect(o.defaultShowIndex);
+        }
+    },
+
+    _assertCard: function (v) {
+        if (!this.layout.isCardExisted(v)) {
+            var card = this.options.cardCreator(v);
+            this.cardMap[v] = card;
+            this.layout.addCardByName(v, card);
+        }
+    },
+
+    setSelect: function (v) {
+        this.tab && this.tab.setValue(v);
+        this._assertCard(v);
+        this.layout.showCardByName(v);
+        if (this.curr !== v) {
+            this.curr = v;
+        }
+    },
+
+    getSelect: function () {
+        return this.curr;
+    },
+
+    getSelectedTab: function () {
+        return this.layout.getShowingCard();
+    },
+
+    getTab: function (v) {
+        this._assertCard(v);
+        return this.layout.getCardByName(v);
+    },
+
+    setValue: function (v) {
+        var card = this.layout.getShowingCard();
+        if (card) {
+            card.setValue(v);
+        }
+    },
+
+    getValue: function () {
+        var card = this.layout.getShowingCard();
+        if (card) {
+            return card.getValue();
+        }
+    },
+
+    populate: function () {
+        var card = this.layout.getShowingCard();
+        if (card) {
+            return card.populate && card.populate.apply(card, arguments);
+        }
+    },
+
+    empty: function () {
+        this.layout.deleteAllCard();
+        this.cardMap = {};
+    },
+
+    destroyed: function () {
+        this.layout.deleteAllCard();
+        this.cardMap = {};
+    }
+});
+BI.Tab.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.tab", BI.Tab);/**
+ * Created by GUY on 2015/8/10.
+ * @class BI.ButtonTree
+ * @extends BI.ButtonGroup
+ */
+
+BI.ButtonTree = BI.inherit(BI.ButtonGroup, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ButtonTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-button-tree"
+        })
+    },
+
+    _init: function () {
+        BI.ButtonTree.superclass._init.apply(this, arguments);
+    },
+
+    setNotSelectedValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (!BI.isFunction(item.setSelected)) {
+                item.setNotSelectedValue(v);
+                return;
+            }
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected(false);
+            } else {
+                item.setSelected(true);
+            }
+        });
+    },
+
+    setEnabledValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.isFunction(item.setEnabledValue)) {
+                item.setEnabledValue(v);
+                return;
+            }
+            if (BI.deepContains(v, item.getValue())) {
+                item.setEnable(true);
+            } else {
+                item.setEnable(false);
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (!BI.isFunction(item.setSelected)) {
+                item.setValue(v);
+                return;
+            }
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected(true);
+            } else {
+                item.setSelected(false);
+            }
+        });
+    },
+
+    getNotSelectedValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !BI.isFunction(item.setSelected)) {
+                v = BI.concat(v, item.getNotSelectedValue());
+                return;
+            }
+            if (item.isEnabled() && item.isSelected && !item.isSelected()) {
+                v.push(item.getValue());
+            }
+        });
+        return v;
+    },
+
+    getValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !BI.isFunction(item.setSelected)) {
+                v = BI.concat(v, item.getValue());
+                return;
+            }
+            if (item.isEnabled() && item.isSelected && item.isSelected()) {
+                v.push(item.getValue());
+            }
+        });
+        return v;
+    },
+
+    getSelectedButtons: function () {
+        var btns = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !BI.isFunction(item.setSelected)) {
+                btns = btns.concat(item.getSelectedButtons());
+                return;
+            }
+            if (item.isSelected && item.isSelected()) {
+                btns.push(item);
+            }
+        });
+        return btns;
+    },
+
+    getNotSelectedButtons: function () {
+        var btns = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !BI.isFunction(item.setSelected)) {
+                btns = btns.concat(item.getNotSelectedButtons());
+                return;
+            }
+            if (item.isSelected && !item.isSelected()) {
+                btns.push(item);
+            }
+        });
+        return btns;
+    },
+
+    //获取所有的叶子节点
+    getAllLeaves: function () {
+        var leaves = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && !BI.isFunction(item.setSelected)) {
+                leaves = leaves.concat(item.getAllLeaves());
+                return;
+            }
+            if (item.isEnabled()) {
+                leaves.push(item);
+            }
+        });
+        return leaves;
+    },
+
+    getIndexByValue: function (value) {
+        var index = -1;
+        BI.any(this.buttons, function (i, item) {
+            var vs = item.getValue();
+            if (item.isEnabled() && (vs === value || BI.contains(vs, value))) {
+                index = i;
+                return true;
+            }
+        });
+        return index;
+    },
+
+    getNodeById: function (id) {
+        var node;
+        BI.any(this.buttons, function (i, item) {
+            if (item.isEnabled()) {
+                if (item.attr("id") === id) {
+                    node = item;
+                    return true;
+                } else if (BI.isFunction(item.getNodeById)) {
+                    if (node = item.getNodeById(id)) {
+                        return true;
+                    }
+                }
+            }
+        });
+        return node;
+    },
+
+    getNodeByValue: function (value) {
+        var node;
+        BI.any(this.buttons, function (i, item) {
+            if (item.isEnabled()) {
+                if (item.getValue() === value) {
+                    node = item;
+                    return true;
+                } else if (BI.isFunction(item.getNodeByValue)) {
+                    if (node = item.getNodeByValue(value)) {
+                        return true;
+                    }
+                }
+            }
+        });
+        return node;
+    }
+});
+BI.ButtonTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.button_tree", BI.ButtonTree);
+
+/**
+ * value作为key值缓存button,  不支持顺序读写
+ * 适合用于频繁增删的一组button
+ * Created by GUY on 2015/8/10.
+ * @class BI.ButtonMap
+ * @extends BI.ButtonTree
+ */
+
+BI.ButtonMap = BI.inherit(BI.ButtonTree, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ButtonMap.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-button-map"
+        })
+    },
+
+    _init: function () {
+        BI.ButtonMap.superclass._init.apply(this, arguments);
+    },
+
+    _createBtns: function (items) {
+        var self = this, o = this.options;
+        var buttons = BI.createWidgets(BI.createItems(items, {type: "bi.text_button", once: o.chooseType === 0}));
+        var keys = BI.map(items, function (i, item) {
+            item = BI.stripEL(item);
+            if (!(item.id || item.value)) {
+                throw new Error("item必须包含id或value属性");
+            }
+            return item.id || item.value;
+        });
+        return BI.object(keys, buttons);
+    },
+
+    setValue: function (v) {
+        var self = this;
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (val, item) {
+            if (!BI.isFunction(item.setSelected)) {
+                item.setValue(v);
+                return;
+            }
+            if (v.contains(val)) {
+                item.setSelected && item.setSelected(true);
+            } else {
+                item.setSelected && item.setSelected(false);
+            }
+        });
+    },
+
+    setNotSelectedValue: function (v) {
+        var self = this;
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (val, item) {
+            if (!BI.isFunction(item.setSelected)) {
+                item.setNotSelectedValue(v);
+                return;
+            }
+            if (v.contains(val)) {
+                item.setSelected && item.setSelected(false);
+            } else {
+                item.setSelected && item.setSelected(true);
+            }
+        });
+    },
+
+    populate: function (items) {
+        var self = this;
+        var args = [].slice.call(arguments);
+        var linkHashMap = new BI.LinkHashMap();
+        var val = function (item) {
+            return item.id || item.value;
+        };
+        if (!this.buttons) {
+            this.buttons = {};
+        }
+        //所有已存在的和新添加的
+        var willCreated = [];
+        BI.each(items, function (i, item) {
+            item = BI.stripEL(item);
+            if (self.buttons[val(item)]) {
+                var ob = self.buttons[val(item)];
+                args[0] = item.items;
+                args[2] = item;
+                ob.populate && ob.populate.apply(ob, args);
+            } else {
+                willCreated.push(item);
+            }
+        });
+        //创建新元素
+        args[0] = willCreated;
+        var newBtns = this._btnsCreator.apply(this, args);
+
+        //整理
+        var array = [];
+        BI.each(items, function (i, item) {
+            item = BI.stripEL(item);
+            var button = self.buttons[val(item)] || newBtns[val(item)];
+            linkHashMap.add(val(item), button);
+            array.push(button);
+        });
+        this.buttons = linkHashMap.map;
+
+        BI.DOM.hang(this.buttons);
+        this.empty();
+
+        var packages = this._packageItems(items, this._packageBtns(array));
+        BI.createWidget(BI.extend({element: this}, this._packageLayout(packages)));
+    },
+
+    getIndexByValue: function (value) {
+        throw new Error("不能使用getIndexByValue方法");
+    }
+});
+BI.ButtonMap.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.button_map", BI.ButtonMap);/**
+ * 表示当前对象
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.EL
+ * @extends BI.Widget
+ */
+BI.EL = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.EL.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-el",
+            el: {},
+            layout: {}
+        });
+    },
+    _init: function () {
+        BI.EL.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.ele = BI.createWidget(o.el);
+        BI.createWidget(o.layout, {
+            type: "bi.adaptive",
+            element: this,
+            items: [this.ele]
+        });
+        this.ele.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        })
+    },
+
+    setValue: function (v) {
+        this.ele.setValue(v);
+    },
+
+    getValue: function () {
+        return this.ele.getValue();
+    },
+
+    populate: function () {
+        this.ele.populate.apply(this, arguments);
+    }
+});
+$.shortcut('bi.el', BI.EL);/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/16.
+ * @class BI.Farbtastic
+ * @extends BI.Widget
+ */
+BI.Farbtastic = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Farbtastic.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-farbtastic",
+            width: 195,
+            height: 195
+        })
+    },
+
+    _init: function () {
+        BI.Farbtastic.superclass._init.apply(this, arguments);
+        var self = this;
+
+        this.farbtastic = $.farbtastic(this.element, function (v) {
+            self.fireEvent(BI.Farbtastic.EVENT_CHANGE, self.getValue(), self);
+        });
+    },
+
+    setValue: function (color) {
+        this.farbtastic.setColor(color);
+    },
+
+    getValue: function () {
+        return this.farbtastic.color;
+    }
+});
+BI.Farbtastic.EVENT_CHANGE = "Farbtastic.EVENT_CHANGE";
+$.shortcut("bi.farbtastic", BI.Farbtastic);;
+(function ($) {
+    /**
+     * 公式编辑控件
+     * @class BI.FormulaEditor
+     * @extends BI.Widget
+     */
+    BI.FormulaEditor = BI.inherit(BI.Single, {
+        _defaultConfig: function () {
+            return $.extend(BI.FormulaEditor.superclass._defaultConfig.apply(), {
+                baseCls: 'bi-formula-editor',
+                watermark: '',
+                value: '',
+                fieldTextValueMap: {}
+            });
+        },
+        _init: function () {
+            BI.FormulaEditor.superclass._init.apply(this, arguments);
+            var o = this.options, self = this;
+            this.editor = CodeMirror(this.element[0], {
+                textWrapping: true,
+                lineWrapping: true,
+                lineNumbers: false,
+                mode: 'formula'
+            });
+            this.editor.on("change", function (cm, change) {
+                self._checkWaterMark();
+                CodeMirror.showHint(cm, CodeMirror.formulaHint, {completeSingle: false});
+                BI.nextTick(function () {
+                    self.fireEvent(BI.FormulaEditor.EVENT_CHANGE)
+                });
+            });
+
+            this.editor.on("focus", function () {
+                self._checkWaterMark();
+                self.fireEvent(BI.FormulaEditor.EVENT_FOCUS);
+            });
+
+            this.editor.on("blur", function () {
+                self.fireEvent(BI.FormulaEditor.EVENT_BLUR);
+            });
+
+
+            if (BI.isKey(o.value)) {
+                self.setValue(o.value);
+            }
+
+            if (BI.isKey(this.options.watermark)) {
+                var self = this;
+                this.watermark = BI.createWidget({
+                    type: "bi.label",
+                    cls: "bi-water-mark",
+                    text: this.options.watermark,
+                    whiteSpace: "nowrap",
+                    textAlign: "left"
+                });
+                BI.createWidget({
+                    type: "bi.absolute",
+                    element: self,
+                    items: [{
+                        el: self.watermark,
+                        left: 0,
+                        top: 0
+                    }]
+                });
+
+                this.watermark.element.bind(
+                    "mousedown", function (e) {
+                        self.insertString("");
+                        self.editor.focus();
+                        e.stopEvent();
+                    }
+                );
+                this.watermark.element.bind("click", function (e) {
+                    self.editor.focus();
+                    e.stopEvent();
+                });
+                this.watermark.element.css({
+                    position: "absolute",
+                    left: 3,
+                    right: 3,
+                    top: 6,
+                    bottom: 0
+                });
+            }
+        },
+
+        _checkWaterMark: function () {
+            var o = this.options;
+            if (!this.disabledWarterMark && BI.isEmptyString(this.editor.getValue()) && BI.isKey(o.watermark)) {
+                this.watermark && this.watermark.visible();
+            } else {
+                this.watermark && this.watermark.invisible();
+            }
+        },
+
+        disableWarterMark: function () {
+            this.disabledWarterMark = true;
+            this._checkWaterMark();
+        },
+
+        /**
+         * 添加字段
+         * @param field
+         */
+        insertField: function (field) {
+            var from = this.editor.getCursor();
+            this.editor.replaceSelection(field);
+            var to = this.editor.getCursor();
+            this.editor.markText(from, to, {className: 'fieldName', atomic: true, startStyle : "start", endStyle:"end"});
+            this.editor.replaceSelection(" ");
+            this.editor.focus();
+        },
+
+        insertFunction: function (fn) {
+            var from = this.editor.getCursor();
+            this.editor.replaceSelection(fn);
+            var to = this.editor.getCursor();
+            this.editor.markText(from, to, {className: "#function", atomic: true});
+            this.editor.replaceSelection("() ");
+            to = this.editor.getCursor();
+            to.ch = to.ch - 2;
+            this.editor.setCursor(to);
+            this.editor.focus();
+        },
+        insertOperator: function (op) {
+            var from = this.editor.getCursor();
+            this.editor.replaceSelection(op);
+            var to = this.editor.getCursor();
+            this.editor.markText(from, to, {className: "%operator", atomic: true});
+            this.editor.replaceSelection(" ");
+            this.editor.focus();
+        },
+
+        setFunction: function (v) {
+            var from = this.editor.getCursor();
+            this.editor.replaceSelection(v);
+            var to = this.editor.getCursor();
+            this.editor.markText(from, to, {className: "#function", atomic: true});
+        },
+
+        insertString: function (str) {
+            this.editor.replaceSelection(str);
+            this.editor.focus();
+        },
+
+        getFormulaString: function () {
+            return this.editor.getValue();
+        },
+
+        getUsedFields: function () {
+            var fieldMap = this.options.fieldTextValueMap;
+            var fields = [];
+            this.editor.getValue(true, function (line) {
+                var value = line.text;
+                _.forEach(line.markedSpans, function (i, ms) {
+                    switch (i.marker.className) {
+                        case "fieldName":
+                            var dId = fieldMap[value.substr(i.from, i.to - i.from)];
+                            if (!fields.contains(dId)) {
+                                fields.push(dId);
+                            }
+
+                    }
+                });
+            });
+            return fields;
+        },
+
+        getCheckString: function () {
+            return this.editor.getValue(true, function (line) {
+                var rawText = line.text, value = line.text, num = 0;
+                value.text = rawText;
+                _.forEach(line.markedSpans, function (i, ms) {
+
+                    switch (i.marker.className) {
+                        case "fieldName":
+                            var fieldNameLength = i.to - i.from;
+                            value = value.substr(0, i.from + num) + "$a" + value.substr(i.to + num, value.length);
+                            num = num + 2 - fieldNameLength;
+                            break;
+                    }
+
+                });
+                return value;
+            });
+        },
+
+        getValue: function () {
+            var fieldMap = this.options.fieldTextValueMap;
+            return this.editor.getValue("\n", function (line) {
+                var rawText = line.text, value = line.text, num = 0;
+                value.text = rawText;
+                _.forEach(line.markedSpans, function (i, ms) {
+                    switch (i.marker.className) {
+                        case "fieldName":
+                            var fieldNameLength = i.to - i.from;
+                            var fieldId = fieldMap[value.substr(i.from + num, fieldNameLength)];
+                            value = value.substr(0, i.from + num) + "$\{" + fieldMap[value.substr(i.from + num, fieldNameLength)] + "\}" + value.substr(i.to + num, value.length);
+                            num += fieldId.length - fieldNameLength + 3;
+                            break;
+                    }
+                });
+                return value;
+            });
+        },
+
+        setValue: function (value) {
+            this.editor.setValue(value);
+        },
+
+        setFieldTextValueMap: function (fieldTextValueMap) {
+            this.options.fieldTextValueMap = fieldTextValueMap;
+        },
+
+        refresh: function () {
+            var self = this;
+            BI.nextTick(function () {
+                self.editor.refresh();
+            });
+        }
+
+    });
+    BI.FormulaEditor.EVENT_CHANGE = "EVENT_CHANGE";
+    BI.FormulaEditor.EVENT_BLUR = "EVENT_BLUR";
+    BI.FormulaEditor.EVENT_FOCUS = "EVENT_FOCUS";
+    $.shortcut("bi.formula", BI.FormulaEditor);
+})(jQuery);
+/**
+ * z-index在1亿层级
+ * 弹出提示消息框,用于模拟阻塞操作(通过回调函数实现)
+ * @class BI.Msg
+ */
+$.extend(BI, {
+    Msg: function () {
+
+        var messageShow, $mask, $pop;
+
+        return {
+            toast: function (message, level, context) {
+                context = context || $("body");
+                var toast = BI.createWidget({
+                    type: "bi.toast",
+                    level: level,
+                    text: message
+                });
+                BI.createWidget({
+                    type: "bi.absolute",
+                    element: context,
+                    items: [{
+                        el: toast,
+                        left: "50%",
+                        top: 0
+                    }]
+                });
+                if (toast.element.outerWidth() > context.outerWidth()) {
+                    toast.setWidth(context.width());
+                }
+                toast.element.css({"margin-left": -1 * toast.element.outerWidth() / 2});
+                toast.invisible();
+                toast.element.slideDown(500, function () {
+                    BI.delay(function () {
+                        toast.element.slideUp(500, function () {
+                            toast.destroy();
+                        })
+                    }, 5000)
+                })
+            },
+            _show: function (hasCancel, title, message, callback) {
+                $mask = $('<div class="bi-message-mask">').css({
+                    position: 'absolute',
+                    'zIndex': 99999998,
+                    top: 0,
+                    left: 0,
+                    right: 0,
+                    bottom: 0,
+                    opacity: 0.1
+                }).appendTo('body');
+                $pop = $('<div class="bi-message-depend">').css({
+                    position: 'absolute',
+                    'zIndex': 99999999,
+                    top: 0,
+                    left: 0,
+                    right: 0,
+                    bottom: 0
+                }).appendTo('body');
+                var close = function () {
+                    messageShow.destroy();
+                    $mask.remove();
+                };
+                var controlItems = [];
+                if (hasCancel === true) {
+                    controlItems.push({
+                        el: {
+                            type: 'bi.button',
+                            text: BI.i18nText("BI-Cancel"),
+                            height: 30,
+                            level: 'ignore',
+                            handler: function () {
+                                close();
+                                if (BI.isFunction(callback)) {
+                                    callback.apply(null, [false]);
+                                }
+                            }
+                        }
+                    });
+                }
+                controlItems.push({
+                    el: {
+                        type: 'bi.button',
+                        text: BI.i18nText("BI-OK"),
+                        height: 30,
+                        handler: function () {
+                            close();
+                            if (BI.isFunction(callback)) {
+                                callback.apply(null, [true]);
+                            }
+                        }
+                    }
+                });
+                var conf = {
+                    element: $pop,
+                    type: 'bi.center_adapt',
+                    items: [
+                        {
+                            type: 'bi.border',
+                            cls: 'bi-message-content',
+                            items: {
+                                'north': {
+                                    el: {
+                                        type: 'bi.border',
+                                        cls: 'bi-message-title',
+                                        items: {
+                                            center: {
+                                                el: {
+                                                    type: 'bi.label',
+                                                    text: title || BI.i18nText("BI-Prompt"),
+                                                    textAlign: 'left',
+                                                    hgap: 20,
+                                                    height: 50
+                                                }
+                                            },
+                                            east: {
+                                                el: {
+                                                    type: 'bi.icon_button',
+                                                    cls: 'bi-message-close close-font',
+//                                                    height: 50,
+                                                    handler: function () {
+                                                        close();
+                                                    }
+                                                },
+                                                width: 60
+                                            }
+                                        }
+                                    },
+                                    height: 50
+                                },
+                                'center': {
+                                    el: {
+                                        type: "bi.text",
+                                        cls: "bi-message-text",
+                                        tgap: 60,
+                                        hgap: 20,
+                                        lineHeight: 30,
+                                        whiteSpace: "normal",
+                                        text: message
+                                    }
+                                },
+                                'south': {
+                                    el: {
+                                        type: "bi.absolute",
+                                        items: [{
+                                            el: {
+                                                type: 'bi.right_vertical_adapt',
+                                                hgap: 5,
+                                                items: controlItems
+                                            },
+                                            top: 0,
+                                            left: 20,
+                                            right: 20,
+                                            bottom: 0
+                                        }]
+
+                                    },
+                                    height: 60
+                                }
+                            },
+                            width: 400,
+                            height: 300
+                        }
+                    ]
+                };
+
+                messageShow = BI.createWidget(conf);
+            }
+        };
+    }()
+});/**
+ * Grid
+ *
+ * Created by GUY on 2016/1/11.
+ * @class BI.Grid
+ * @extends BI.Widget
+ */
+BI.Grid = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Grid.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-grid",
+            width: 400,
+            height: 300,
+            overflowX: true,
+            overflowY: true,
+            overscanColumnCount: 0,
+            overscanRowCount: 0,
+            rowHeightGetter: BI.emptyFn,
+            columnWidthGetter: BI.emptyFn,
+            estimatedColumnSize: 100,
+            estimatedRowSize: 30,
+            scrollLeft: 0,
+            scrollTop: 0,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.Grid.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.renderedCells = [];
+        this.renderedKeys = [];
+        this._scrollLock = false;
+        this._debounceRelease = BI.debounce(function () {
+            self._scrollLock = false;
+        }, 150);
+        this.container = BI.createWidget({
+            type: "bi.absolute"
+        });
+        this.element.scroll(function () {
+            if (self._scrollLock === true) {
+                return;
+            }
+            o.scrollLeft = self.element.scrollLeft();
+            o.scrollTop = self.element.scrollTop();
+            self._calculateChildrenToRender();
+            self.fireEvent(BI.Grid.EVENT_SCROLL, {
+                scrollLeft: o.scrollLeft,
+                scrollTop: o.scrollTop
+            });
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            scrollable: o.overflowX === true && o.overflowY === true,
+            scrolly: o.overflowX === false && o.overflowY === true,
+            scrollx: o.overflowX === true && o.overflowY === false,
+            items: [this.container]
+        });
+        if (o.items.length > 0) {
+            this._populate();
+        }
+    },
+
+    mounted: function () {
+        var o = this.options;
+        if (o.scrollLeft !== 0 || o.scrollTop !== 0) {
+            this.element.scrollTop(o.scrollTop);
+            this.element.scrollLeft(o.scrollLeft);
+        }
+    },
+
+    _getOverscanIndices: function (cellCount, overscanCellsCount, startIndex, stopIndex) {
+        return {
+            overscanStartIndex: Math.max(0, startIndex - overscanCellsCount),
+            overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount)
+        }
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+
+        var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()),
+            overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount;
+
+        if (height > 0 && width > 0) {
+            var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft);
+            var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop);
+
+            var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft);
+            var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop);
+
+            this._renderedColumnStartIndex = visibleColumnIndices.start;
+            this._renderedColumnStopIndex = visibleColumnIndices.stop;
+            this._renderedRowStartIndex = visibleRowIndices.start;
+            this._renderedRowStopIndex = visibleRowIndices.stop;
+
+            var overscanColumnIndices = this._getOverscanIndices(this.columnCount, overscanColumnCount, this._renderedColumnStartIndex, this._renderedColumnStopIndex)
+
+            var overscanRowIndices = this._getOverscanIndices(this.rowCount, overscanRowCount, this._renderedRowStartIndex, this._renderedRowStopIndex);
+
+            var columnStartIndex = overscanColumnIndices.overscanStartIndex;
+            var columnStopIndex = overscanColumnIndices.overscanStopIndex;
+            var rowStartIndex = overscanRowIndices.overscanStartIndex;
+            var rowStopIndex = overscanRowIndices.overscanStopIndex;
+
+            var renderedCells = [], renderedKeys = [];
+
+            for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
+                var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex);
+
+                for (var columnIndex = columnStartIndex; columnIndex <= columnStopIndex; columnIndex++) {
+                    var key = [rowIndex, columnIndex];
+                    var columnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnIndex);
+
+                    var index = BI.deepIndexOf(this.renderedKeys, key);
+                    if (index > -1) {
+                        if (columnDatum.size !== this.renderedCells[index]._width) {
+                            this.renderedCells[index]._width = columnDatum.size;
+                            this.renderedCells[index].el.setWidth(columnDatum.size);
+                        }
+                        if (rowDatum.size !== this.renderedCells[index]._height) {
+                            this.renderedCells[index]._height = rowDatum.size;
+                            this.renderedCells[index].el.setHeight(rowDatum.size);
+                        }
+                        if (this.renderedCells[index].left !== columnDatum.offset + horizontalOffsetAdjustment) {
+                            this.renderedCells[index].el.element.css("left", (columnDatum.offset + horizontalOffsetAdjustment) + "px");
+                        }
+                        if (this.renderedCells[index].top !== rowDatum.offset + verticalOffsetAdjustment) {
+                            this.renderedCells[index].el.element.css("top", (rowDatum.offset + verticalOffsetAdjustment) + "px");
+                        }
+                        renderedCells.push(this.renderedCells[index]);
+                    } else {
+                        var child = BI.createWidget(BI.extend({
+                            type: "bi.label",
+                            width: columnDatum.size,
+                            height: rowDatum.size
+                        }, o.items[rowIndex][columnIndex], {
+                            cls: (o.items[rowIndex][columnIndex].cls || "") + " grid-cell" + (rowIndex === 0 ? " first-row" : "") + (columnIndex === 0 ? " first-col" : ""),
+                            _rowIndex: rowIndex,
+                            _columnIndex: columnIndex,
+                            _left: columnDatum.offset + horizontalOffsetAdjustment,
+                            _top: rowDatum.offset + verticalOffsetAdjustment
+                        }));
+                        renderedCells.push({
+                            el: child,
+                            left: columnDatum.offset + horizontalOffsetAdjustment,
+                            top: rowDatum.offset + verticalOffsetAdjustment,
+                            _width: columnDatum.size,
+                            _height: rowDatum.size
+                        });
+                    }
+                    renderedKeys.push(key);
+                }
+            }
+            //已存在的, 需要添加的和需要删除的
+            var existSet = {}, addSet = {}, deleteArray = [];
+            BI.each(renderedKeys, function (i, key) {
+                if (BI.deepContains(self.renderedKeys, key)) {
+                    existSet[i] = key;
+                } else {
+                    addSet[i] = key;
+                }
+            });
+            BI.each(this.renderedKeys, function (i, key) {
+                if (BI.deepContains(existSet, key)) {
+                    return;
+                }
+                if (BI.deepContains(addSet, key)) {
+                    return;
+                }
+                deleteArray.push(i);
+            });
+            BI.each(deleteArray, function (i, index) {
+                self.renderedCells[index].el.destroy();
+            });
+            var addedItems = [];
+            BI.each(addSet, function (index) {
+                addedItems.push(renderedCells[index])
+            });
+            BI.createWidget({
+                type: "bi.absolute",
+                element: this.container,
+                items: addedItems
+            });
+            this.renderedCells = renderedCells;
+            this.renderedKeys = renderedKeys;
+        }
+    },
+
+    _getMaxScrollLeft: function () {
+        return Math.max(0, this._columnSizeAndPositionManager.getTotalSize() - this.options.width + (this.options.overflowX ? BI.DOM.getScrollWidth() : 0));
+    },
+
+    _getMaxScrollTop: function () {
+        return Math.max(0, this._rowSizeAndPositionManager.getTotalSize() - this.options.height + (this.options.overflowY ? BI.DOM.getScrollWidth() : 0));
+    },
+
+    _populate: function () {
+        var self = this, o = this.options;
+        if (o.items.length > 0) {
+            this.columnCount = o.items[0].length;
+            this.rowCount = o.items.length;
+            this.container.setWidth(this.columnCount * o.estimatedColumnSize);
+            this.container.setHeight(this.rowCount * o.estimatedRowSize);
+
+            this._columnSizeAndPositionManager = new BI.ScalingCellSizeAndPositionManager(this.columnCount, o.columnWidthGetter, o.estimatedColumnSize);
+            this._rowSizeAndPositionManager = new BI.ScalingCellSizeAndPositionManager(this.rowCount, o.rowHeightGetter, o.estimatedRowSize);
+
+            this._calculateChildrenToRender();
+            this.element.scrollTop(o.scrollTop);
+            this.element.scrollLeft(o.scrollLeft);
+        }
+    },
+
+    setScrollLeft: function (scrollLeft) {
+        if (this.options.scrollLeft === scrollLeft) {
+            return;
+        }
+        this._scrollLock = true;
+        this.options.scrollLeft = BI.clamp(scrollLeft || 0, 0, this._getMaxScrollLeft());
+        this._debounceRelease();
+        this._calculateChildrenToRender();
+        this.element.scrollLeft(this.options.scrollLeft);
+    },
+
+    setScrollTop: function (scrollTop) {
+        if (this.options.scrollTop === scrollTop) {
+            return;
+        }
+        this._scrollLock = true;
+        this.options.scrollTop = BI.clamp(scrollTop || 0, 0, this._getMaxScrollTop());
+        this._debounceRelease();
+        this._calculateChildrenToRender();
+        this.element.scrollTop(this.options.scrollTop);
+    },
+
+    setOverflowX: function (b) {
+        var self = this;
+        if (this.options.overflowX !== !!b) {
+            this.options.overflowX = !!b;
+            BI.nextTick(function () {
+                self.element.css({overflowX: !!b ? "auto" : "hidden"});
+            });
+        }
+    },
+
+    setOverflowY: function (b) {
+        var self = this;
+        if (this.options.overflowY !== !!b) {
+            this.options.overflowY = !!b;
+            BI.nextTick(function () {
+                self.element.css({overflowY: !!b ? "auto" : "hidden"});
+            });
+        }
+    },
+
+    getScrollLeft: function () {
+        return this.options.scrollLeft;
+    },
+
+    getScrollTop: function () {
+        return this.options.scrollTop;
+    },
+
+    getMaxScrollLeft: function () {
+        return this._getMaxScrollLeft();
+    },
+
+    getMaxScrollTop: function () {
+        return this._getMaxScrollTop();
+    },
+
+    setEstimatedColumnSize: function (width) {
+        this.options.estimatedColumnSize = width;
+    },
+
+    setEstimatedRowSize: function (height) {
+        this.options.estimatedRowSize = height;
+    },
+
+    restore: function () {
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+        this._scrollLock = false;
+    },
+
+    populate: function (items) {
+        if (items && items !== this.options.items) {
+            this.options.items = items;
+            this.restore();
+        }
+        this._populate();
+    }
+});
+BI.Grid.EVENT_SCROLL = "EVENT_SCROLL";
+$.shortcut('bi.grid_view', BI.Grid);/**
+ * floatBox弹出层,
+ * @class BI.FloatBox
+ * @extends BI.Widget
+ */
+BI.FloatBox = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FloatBox.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-float-box",
+            width: 600,
+            height: 500
+        })
+    },
+    _init: function () {
+        BI.FloatBox.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.showAction = new BI.ShowAction({
+            tar: this
+        });
+        this._center = BI.createWidget();
+        this._north = BI.createWidget();
+        this.element.draggable({
+            cursor: BICst.cursorUrl,
+            handle: ".bi-message-title",
+            drag: function (e, ui) {
+                var W = $("body").width(), H = $("body").height();
+                if (ui.position.left + o.width > W) {
+                    ui.position.left = W - o.width;
+                }
+                if (ui.position.top + o.height > H) {
+                    ui.position.top = H - o.height;
+                }
+                if (ui.position.left < 0) {
+                    ui.position.left = 0;
+                }
+                if (ui.position.top < 0) {
+                    ui.position.top = 0;
+                }
+            }
+        });
+        this._south = BI.createWidget();
+        BI.createWidget({
+            type: 'bi.border',
+            element: this,
+            items: {
+                'north': {
+                    el: {
+                        type: 'bi.border',
+                        cls: 'bi-message-title',
+                        items: {
+                            center: {
+                                el: {
+                                    type: "bi.absolute",
+                                    items: [{
+                                        el: this._north,
+                                        left: 10,
+                                        top: 0,
+                                        right: 0,
+                                        bottom: 0
+                                    }]
+                                }
+                            },
+                            east: {
+                                el: {
+                                    type: 'bi.icon_button',
+                                    cls: 'bi-message-close close-font',
+                                    height: 50,
+                                    handler: function () {
+                                        self.currentSectionProvider.close();
+                                    }
+                                },
+                                width: 60
+                            }
+                        }
+                    },
+                    height: 50
+                },
+                'center': {
+                    el: {
+                        type: "bi.absolute",
+                        items: [{
+                            el: this._center,
+                            left: 10,
+                            top: 10,
+                            right: 10,
+                            bottom: 10
+                        }]
+                    }
+                },
+                'south': {
+                    el: {
+                        type: "bi.absolute",
+                        items: [{
+                            el: this._south,
+                            left: 10,
+                            top: 0,
+                            right: 10,
+                            bottom: 0
+                        }]
+                    },
+                    height: 60
+                }
+            }
+        })
+    },
+
+    populate: function (sectionProvider) {
+        var self = this;
+        this.currentSectionProvider = sectionProvider;
+        sectionProvider.rebuildNorth(this._north);
+        sectionProvider.rebuildCenter(this._center);
+        sectionProvider.rebuildSouth(this._south);
+        if (sectionProvider instanceof BI.Widget) {
+            sectionProvider.on(BI.PopoverSection.EVENT_CLOSE, function () {
+                self.close();
+            })
+        }
+    },
+
+    show: function () {
+        this.showAction.actionPerformed();
+    },
+
+    hide: function () {
+        this.showAction.actionBack();
+    },
+
+    open: function () {
+        this.show();
+        this.fireEvent(BI.FloatBox.EVENT_FLOAT_BOX_OPEN);
+    },
+
+    close: function () {
+        this.hide();
+        this.fireEvent(BI.FloatBox.EVENT_FLOAT_BOX_CLOSED);
+    },
+
+    setZindex: function (zindex) {
+        this.element.css({"z-index": zindex});
+    }
+});
+
+$.shortcut("bi.float_box", BI.FloatBox);
+
+BI.FloatBox.EVENT_FLOAT_BOX_CLOSED = "EVENT_FLOAT_BOX_CLOSED";
+BI.FloatBox.EVENT_FLOAT_BOX_OPEN = "EVENT_FLOAT_BOX_CLOSED";
+/**
+ * 下拉框弹出层, zIndex在1000w
+ * @class BI.PopupView
+ * @extends BI.Widget
+ */
+BI.PopupView = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.PopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-list-view",
+            maxWidth: 'auto',
+            minWidth: 100,
+            //maxHeight: 200,
+            minHeight: 25,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            vgap: 0,
+            hgap: 0,
+            direction: BI.Direction.Top, //工具栏的方向
+            stopEvent: false,//是否停止mousedown、mouseup事件
+            stopPropagation: false, //是否停止mousedown、mouseup向上冒泡
+            logic: {
+                dynamic: true
+            },
+
+            tool: false, //自定义工具栏
+            tabs: [], //导航栏
+            buttons: [], //toolbar栏
+
+            el: {
+                type: "bi.button_group",
+                items: [],
+                chooseType: 0,
+                behaviors: {},
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        })
+    },
+
+    _init: function () {
+        BI.PopupView.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var fn = function (e) {
+            e.stopPropagation();
+        }, stop = function (e) {
+            e.stopEvent();
+            return false;
+        };
+        this.element.css({
+            "z-index": BI.zIndex_popup,
+            "min-width": o.minWidth + "px",
+            "max-width": o.maxWidth + "px"
+        }).bind({"click": fn, "mousewheel": fn});
+
+        o.stopPropagation && this.element.bind({"mousedown": fn, "mouseup": fn, "mouseover": fn});
+        o.stopEvent && this.element.bind({"mousedown": stop, "mouseup": stop, "mouseover": stop});
+        this.tool = this._createTool();
+        this.tab = this._createTab();
+        this.view = this._createView();
+        this.toolbar = this._createToolBar();
+
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.PopupView.EVENT_CHANGE);
+            }
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+            scrolly: false,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            vgap: o.vgap,
+            hgap: o.hgap,
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction,
+                BI.extend({
+                    cls: "list-view-outer"
+                }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+                    items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tool, this.tab, this.view, this.toolbar)
+                })))
+            )
+        }))));
+    },
+
+    _createView: function () {
+        var o = this.options;
+        this.button_group = BI.createWidget(o.el, {type: "bi.button_group"});
+        this.button_group.element.css({"min-height": o.minHeight + "px"});
+        return this.button_group;
+    },
+
+    _createTool: function () {
+        var o = this.options;
+        if (false === o.tool) {
+            return;
+        }
+        return BI.createWidget(o.tool)
+    },
+
+    _createTab: function () {
+        var o = this.options;
+        if (o.tabs.length === 0) {
+            return;
+        }
+        return BI.createWidget({
+            type: "bi.center",
+            cls: "list-view-tab",
+            height: 25,
+            items: o.tabs
+        })
+    },
+
+    _createToolBar: function () {
+        var o = this.options;
+        if (o.buttons.length === 0) {
+            return;
+        }
+
+        return BI.createWidget({
+            type: "bi.center",
+            cls: "list-view-toolbar",
+            height: 30,
+            items: BI.createItems(o.buttons, {
+                once: false,
+                shadow: true,
+                isShadowShowingOnSelected: true
+            })
+        })
+    },
+
+    populate: function (items) {
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    resetWidth: function (w) {
+        this.options.width = w;
+        this.element.width(w);
+    },
+
+    resetHeight: function (h) {
+        var tbHeight = 30 * (this.toolbar ? 1 : 0),
+            tabHeight = 25 * (this.tab ? 1 : 0),
+            toolHeight = ((this.tool && this.tool.element.outerHeight()) || 25) * ((this.tool && this.tool.isVisible()) ? 1 : 0);
+        this.view.resetHeight ? this.view.resetHeight(h - tbHeight - tabHeight - toolHeight - 2) :
+            this.view.element.css({"max-height": (h - tbHeight - tabHeight - toolHeight - 2) + "px"})
+    },
+
+    setEnable: function (arg) {
+        BI.PopupView.superclass.setEnable.apply(this, arguments);
+        this.view && this.view.setEnable(arg);
+    },
+
+    setValue: function (selectedValues) {
+        this.tab && this.tab.setValue(selectedValues);
+        this.button_group.setValue(selectedValues);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    }
+});
+BI.PopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.popup_view", BI.PopupView);/**
+ * guy
+ * @class BI.ScrollView
+ * @extends BI.Widget
+ */
+BI.ScrollView = BI.inherit(BI.Widget, {
+
+    _const: {
+        dropDownHeight: 15,
+        expandIcon: "column-next-page-h-font",
+        collapseIcon: "column-pre-page-h-font"
+    },
+
+    _defaultConfig: function() {
+        return BI.extend(BI.ScrollView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:"bi-scroll-view",
+            scrollHeight: 50,
+            maxHeight: 300
+        })
+    },
+
+    _init : function() {
+        BI.ScrollView.superclass._init.apply(this, arguments);
+
+        this.scrollUp = false;
+        this.scroll = BI.createWidget({
+            type: "bi.vertical",
+            cls: "scroll-container",
+            scrolly: true
+        })
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            scrolly: false,
+            items: [this.scroll]
+        })
+
+        this.dropdown = BI.createWidget({
+            type: "bi.icon_button",
+            height: this._const.dropDownHeight,
+            cls: "scroll-drop-down-icon " + this._const.expandIcon,
+            handler: BI.bind(this._dropDownOrUp, this)
+        })
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.dropdown,
+                left: 0,
+                right: 0,
+                bottom: -1 * this._const.dropDownHeight
+            }]
+        })
+        this.populate(this.options.items);
+    },
+
+    _dropDownOrUp: function(){
+        if(!this.scrollUp){
+            var height = this.element.height();
+            height += this.options.scrollHeight;
+            height = Math.min(height, this.scroll.element[0].scrollHeight, this.options.maxHeight);
+            this.element.height(height);
+            this._checkDropDownState();
+        } else {
+            var height = this.element.height();
+            height -= this.options.scrollHeight;
+            height = Math.max(height, this.options.height);
+            this.element.height(height);
+            this._checkDropDownState();
+        }
+    },
+
+    _checkDropDownState: function(){
+        var height = this.element.height();
+        if(!this._checkScroll() || height >= this.options.maxHeight){
+            this.scrollUp = true;
+            this.dropdown.element.removeClass(this._const.expandIcon).addClass(this._const.collapseIcon);
+        } else if(height <= this.options.height){
+            this.scrollUp = false;
+            this.dropdown.element.addClass(this._const.expandIcon);
+        } else {
+            this.dropdown.element.addClass(this.scrollUp ? this._const.collapseIcon : this._const.expandIcon);
+        }
+    },
+
+    _checkScroll: function(){
+        this.scroll.element.height(this.element.height());
+        return this.scroll.element[0].scrollHeight > this.scroll.element[0].clientHeight;
+    },
+
+    _checkDropDown: function(){
+        if(this._checkScroll()){
+            this.dropdown.visible();
+            //this.scrollUp = false;
+            this._checkDropDownState();
+        } else {
+            this.dropdown.invisible();
+        }
+    },
+
+    populate: function(){
+        this.scroll.populate.apply(this.scroll, arguments);
+        this.resize();
+    },
+
+    resize: function(){
+        this.element.height(this.options.height);
+        BI.nextTick(BI.bind(this._checkDropDown, this));
+    },
+
+    addItem: function(){
+        this.scroll.addItem.apply(this.scroll, arguments);
+        BI.nextTick(BI.bind(this._checkDropDown, this));
+    }
+});
+
+$.shortcut("bi.scroll_view", BI.ScrollView);/**
+ * 搜索面板
+ *
+ * Created by GUY on 2015/9/28.
+ * @class BI.SearcherView
+ * @extends BI.Pane
+ */
+
+BI.SearcherView = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        var conf = BI.SearcherView.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-searcher-view",
+            tipText: BI.i18nText("BI-No_Select"),
+            chooseType: BI.Selection.Single,
+
+            matcher: {//完全匹配的构造器
+                type: "bi.button_group",
+                behaviors: {
+                    redmark: function () {
+                        return true;
+                    }
+                },
+                items: [],
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            },
+            searcher: {
+                type: "bi.button_group",
+                behaviors: {
+                    redmark: function () {
+                        return true;
+                    }
+                },
+                items: [],
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        })
+    },
+
+    _init: function () {
+        BI.SearcherView.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.matcher = BI.createWidget(o.matcher, {
+            type: "bi.button_group",
+            chooseType: o.chooseType,
+            behaviors: {
+                redmark: function () {
+                    return true;
+                }
+            },
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.matcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob);
+            }
+        });
+        this.spliter = BI.createWidget({
+            type: "bi.vertical",
+            height: 1,
+            hgap: 10,
+            items: [{
+                type: "bi.layout",
+                height: 1,
+                cls: "searcher-view-spliter"
+            }]
+        });
+        this.searcher = BI.createWidget(o.searcher, {
+            type: "bi.button_group",
+            chooseType: o.chooseType,
+            behaviors: {
+                redmark: function () {
+                    return true;
+                }
+            },
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.searcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.matcher, this.spliter, this.searcher]
+        });
+    },
+
+    startSearch: function () {
+
+    },
+
+    stopSearch: function () {
+
+    },
+
+    setValue: function (v) {
+        this.matcher.setValue(v);
+        this.searcher.setValue(v);
+    },
+
+    getValue: function () {
+        return this.matcher.getValue().concat(this.searcher.getValue());
+    },
+
+    populate: function (searchResult, matchResult, keyword) {
+        searchResult || (searchResult = []);
+        matchResult || (matchResult = []);
+        this.setTipVisible(searchResult.length + matchResult.length === 0);
+        this.spliter.setVisible(BI.isNotEmptyArray(matchResult) && BI.isNotEmptyArray(searchResult));
+        this.matcher.populate(matchResult, keyword);
+        this.searcher.populate(searchResult, keyword);
+    },
+
+    empty: function () {
+        this.searcher.empty();
+        this.matcher.empty();
+    },
+
+    hasMatched: function () {
+        return this.matcher.getAllButtons().length > 0;
+    }
+});
+BI.SearcherView.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.searcher_view", BI.SearcherView);/**
+ * 分页控件
+ *
+ * Created by GUY on 2015/8/31.
+ * @class BI.Pager
+ * @extends BI.Widget
+ */
+BI.Pager = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Pager.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-pager",
+            behaviors: {},
+            layouts: [{
+                type: "bi.horizontal",
+                hgap: 10,
+                vgap: 0
+            }],
+
+            dynamicShow: true, //是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态
+            //dynamicShow为false时以下两个有用
+            dynamicShowFirstLast: false,//是否动态显示首页、尾页
+            dynamicShowPrevNext: false,//是否动态显示上一页、下一页
+            pages: false, //总页数
+            curr: function () {
+                return 1;
+            }, //初始化当前页
+            groups: 0, //连续显示分页数
+            jump: BI.emptyFn, //分页的回调函数
+
+            first: false, //是否显示首页
+            last: false, //是否显示尾页
+            prev: "上一页",
+            next: "下一页",
+
+            firstPage: 1,
+            lastPage: function () { //在万不得已时才会调用这个函数获取最后一页的页码,  主要作用于setValue方法
+                return 1;
+            },
+            hasPrev: BI.emptyFn, //pages不可用时有效
+            hasNext: BI.emptyFn  //pages不可用时有效
+        })
+    },
+    _init: function () {
+        BI.Pager.superclass._init.apply(this, arguments);
+        var self = this;
+        this.currPage = BI.result(this.options, "curr");
+        //翻页太灵敏
+        this._lock = false;
+        this._debouce = BI.debounce(function () {
+            self._lock = false;
+        }, 300);
+        this._populate();
+    },
+
+    populate: function () {
+        this.currPage = BI.result(this.options, "curr");
+        this._populate();
+    },
+    
+    refresh: function () {
+        this._populate();  
+    },
+
+    _populate: function () {
+        var self = this, o = this.options, view = [], dict = {};
+        this.empty();
+        var pages = BI.result(o, "pages");
+        var curr = BI.result(this, "currPage");
+        var groups = BI.result(o, "groups");
+        var first = BI.result(o, "first");
+        var last = BI.result(o, "last");
+        var prev = BI.result(o, "prev");
+        var next = BI.result(o, "next");
+
+        if (pages === false) {
+            groups = 0;
+            first = false;
+            last = false;
+        } else {
+            groups > pages && (groups = pages);
+        }
+
+        //计算当前组
+        dict.index = Math.ceil((curr + ((groups > 1 && groups !== pages) ? 1 : 0)) / (groups === 0 ? 1 : groups));
+
+        //当前页非首页,则输出上一页
+        if (((!o.dynamicShow && !o.dynamicShowPrevNext) || curr > 1) && prev !== false) {
+            if (BI.isKey(prev)) {
+                view.push({
+                    text: prev,
+                    value: "prev",
+                    disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false)
+                })
+            } else {
+                view.push(BI.extend({
+                    disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false)
+                }, prev));
+            }
+        }
+
+        //当前组非首组,则输出首页
+        if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (dict.index > 1 && groups !== 0)) && first) {
+            view.push({
+                text: first,
+                value: "first",
+                disabled: !(dict.index > 1 && groups !== 0)
+            });
+            if (dict.index > 1 && groups !== 0) {
+                view.push({
+                    type: "bi.label",
+                    cls: "page-ellipsis",
+                    text: "\u2026"
+                });
+            }
+        }
+
+        //输出当前页组
+        dict.poor = Math.floor((groups - 1) / 2);
+        dict.start = dict.index > 1 ? curr - dict.poor : 1;
+        dict.end = dict.index > 1 ? (function () {
+            var max = curr + (groups - dict.poor - 1);
+            return max > pages ? pages : max;
+        }()) : groups;
+        if (dict.end - dict.start < groups - 1) { //最后一组状态
+            dict.start = dict.end - groups + 1;
+        }
+        var s = dict.start, e = dict.end;
+        if (first && last && (dict.index > 1 && groups !== 0) && (pages > groups && dict.end < pages && groups !== 0)) {
+            s++;
+            e--;
+        }
+        for (; s <= e; s++) {
+            if (s === curr) {
+                view.push({
+                    text: s,
+                    value: s,
+                    selected: true
+                })
+            } else {
+                view.push({
+                    text: s,
+                    value: s
+                })
+            }
+        }
+
+        //总页数大于连续分页数,且当前组最大页小于总页,输出尾页
+        if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (pages > groups && dict.end < pages && groups !== 0)) && last) {
+            if (pages > groups && dict.end < pages && groups !== 0) {
+                view.push({
+                    type: "bi.label",
+                    cls: "page-ellipsis",
+                    text: "\u2026"
+                });
+            }
+            view.push({
+                text: last,
+                value: "last",
+                disabled: !(pages > groups && dict.end < pages && groups !== 0)
+            })
+        }
+
+        //当前页不为尾页时,输出下一页
+        dict.flow = !prev && groups === 0;
+        if (((!o.dynamicShow && !o.dynamicShowPrevNext) && next) || (curr !== pages && next || dict.flow)) {
+            view.push((function () {
+                if (BI.isKey(next)) {
+                    if (pages === false) {
+                        return {text: next, value: "next", disabled: o.hasNext(curr) === false}
+                    }
+                    return (dict.flow && curr === pages)
+                        ?
+                    {text: next, value: "next", disabled: true}
+                        :
+                    {text: next, value: "next", disabled: !(curr !== pages && next || dict.flow)};
+                } else {
+                    return BI.extend({
+                        disabled: pages === false ? o.hasNext(curr) === false : !(curr !== pages && next || dict.flow)
+                    }, next);
+                }
+            }()));
+        }
+
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(view, {
+                cls: "page-item",
+                height: 23,
+                hgap: 10
+            }),
+            behaviors: o.behaviors,
+            layouts: o.layouts
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (self._lock === true) {
+                return;
+            }
+            self._lock = true;
+            self._debouce();
+            if (type === BI.Events.CLICK) {
+                var v = self.button_group.getValue()[0];
+                switch (v) {
+                    case "first":
+                        self.currPage = 1;
+                        break;
+                    case "last":
+                        self.currPage = pages;
+                        break;
+                    case "prev":
+                        self.currPage--;
+                        break;
+                    case "next":
+                        self.currPage++;
+                        break;
+                    default:
+                        self.currPage = v;
+                        break;
+                }
+                o.jump.apply(self, [{
+                    pages: pages,
+                    curr: self.currPage
+                }]);
+                self._populate();
+                self.fireEvent(BI.Pager.EVENT_CHANGE, obj);
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.fireEvent(BI.Pager.EVENT_AFTER_POPULATE);
+    },
+
+    getCurrentPage: function () {
+        return this.currPage;
+    },
+
+    setAllPages: function (pages) {
+        this.options.pages = pages;
+    },
+
+    hasPrev: function (v) {
+        v || (v = 1);
+        var o = this.options;
+        var pages = this.options.pages;
+        return pages === false ? o.hasPrev(v) : v > 1;
+    },
+
+    hasNext: function (v) {
+        v || (v = 1);
+        var o = this.options;
+        var pages = this.options.pages;
+        return pages === false ? o.hasNext(v) : v < pages;
+    },
+
+    setValue: function (v) {
+        var o = this.options;
+        v = v | 0;
+        v = v < 1 ? 1 : v;
+        if (o.pages === false) {
+            var lastPage = BI.result(o, "lastPage"), firstPage = 1;
+            this.currPage = v > lastPage ? lastPage : ((firstPage = BI.result(o, "firstPage")), (v < firstPage ? firstPage : v));
+        } else {
+            v = v > o.pages ? o.pages : v;
+            this.currPage = v;
+        }
+        this._populate();
+    },
+
+    getValue: function () {
+        var val = this.button_group.getValue()[0];
+        switch (val) {
+            case "prev":
+                return -1;
+            case "next":
+                return 1;
+            case "first":
+                return BI.MIN;
+            case "last":
+                return BI.MAX;
+            default :
+                return val;
+        }
+    }
+});
+BI.Pager.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Pager.EVENT_AFTER_POPULATE = "EVENT_AFTER_POPULATE";
+$.shortcut("bi.pager", BI.Pager);/**
+ * 超链接
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.A
+ * @extends BI.Text
+ * @abstract
+ */
+BI.A = BI.inherit(BI.Text, {
+    _defaultConfig: function () {
+        var conf = BI.A.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-a display-block",
+            href: "",
+            target: "_blank",
+            el: null
+        })
+    },
+    _init: function () {
+        var o = this.options;
+        this.options.element = $("<a href='" + o.href + "' target='" + o.target + "'>");
+        BI.A.superclass._init.apply(this, arguments);
+        if (o.el) {
+            BI.createWidget(o.el, {
+                element: this
+            });
+        }
+    }
+});
+
+$.shortcut("bi.a", BI.A);/**
+ * guy
+ * 加载条
+ * @type {*|void|Object}
+ */
+BI.LoadingBar = BI.inherit(BI.Single, {
+    consts: {
+        loadedText: '加载更多',
+        endText: '无更多数据'
+    },
+    _defaultConfig: function() {
+        var conf = BI.LoadingBar.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            baseCls : (conf.baseCls ||"")+' bi-loading-bar',
+            height: 30,
+            handler: BI.emptyFn
+        })
+    },
+    _init : function() {
+        BI.LoadingBar.superclass._init.apply(this, arguments);
+        var self = this;
+        this.loaded = BI.createWidget({
+            type: "bi.text_button",
+            cls: "loading-text",
+            text: this.consts.loadedText,
+            width: 120,
+            handler: this.options.handler
+        })
+        this.loaded.on(BI.Controller.EVENT_CHANGE, function(type){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        })
+
+        this.loading = BI.createWidget({
+            type: "bi.layout",
+            height:this.options.height,
+            cls: "loading-background cursor-default"
+        })
+        var loaded = BI.createWidget({
+            type: "bi.center_adapt",
+            items: [this.loaded]
+        })
+        var loading = BI.createWidget({
+            type: "bi.center_adapt",
+            items: [this.loading]
+        })
+        this.cardLayout = BI.createWidget({
+            type: "bi.card",
+            element: this,
+            items: [{
+                el: loaded,
+                cardName: "loaded"
+            }, {
+                el: loading,
+                cardName: "loading"
+            }]
+        })
+        this.invisible();
+    },
+
+    _reset: function(){
+        this.visible();
+        this.loaded.setText(this.consts.loadedText);
+        this.loaded.enable();
+    },
+
+    setLoaded: function(){
+        this._reset();
+        this.cardLayout.showCardByName("loaded");
+    },
+
+    setEnd: function(){
+        this.setLoaded();
+        this.loaded.setText(this.consts.endText);
+        this.loaded.disable();
+    },
+
+    setLoading: function(){
+        this._reset();
+        this.cardLayout.showCardByName("loading");
+    }
+});
+
+$.shortcut("bi.loading_bar", BI.LoadingBar);/**
+ * @class BI.IconButton
+ * @extends BI.BasicButton
+ * 图标的button
+ */
+BI.IconButton = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        var conf = BI.IconButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            tagName: "a",
+            baseCls: (conf.baseCls || "") + " bi-icon-button horizon-center display-block",
+            iconWidth: null,
+            iconHeight: null
+        })
+    },
+
+    _init: function () {
+        BI.IconButton.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.element.css({
+            textAlign: 'center'
+        });
+        this.icon = BI.createWidget({
+            type: 'bi.icon',
+            width: o.iconWidth,
+            height: o.iconHeight
+        });
+        if (BI.isNumber(o.height) && o.height > 0 && BI.isNull(o.iconWidth) && BI.isNull(o.iconHeight)) {
+            this.element.css("lineHeight", o.height + "px");
+            BI.createWidget({
+                type: "bi.default",
+                element: this,
+                items: [this.icon]
+            })
+        } else {
+            BI.createWidget({
+                element: this,
+                type: 'bi.center_adapt',
+                items: [this.icon]
+            });
+        }
+    },
+
+    doClick: function () {
+        BI.IconButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.IconButton.EVENT_CHANGE, this);
+        }
+    }
+});
+BI.IconButton.EVENT_CHANGE = "IconButton.EVENT_CHANGE";
+$.shortcut("bi.icon_button", BI.IconButton);/**
+ * 图片的button
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.ImageButton
+ * @extends BI.BasicButton
+ */
+BI.ImageButton = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        var conf = BI.ImageButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            tagName: "a",
+            baseCls: (conf.baseCls || "") + " bi-image-button display-block",
+            src: "",
+            iconWidth: "100%",
+            iconHeight: "100%"
+        })
+    },
+
+    _init: function () {
+        BI.ImageButton.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.image = BI.createWidget({
+            type: "bi.img",
+            width: o.iconWidth,
+            height: o.iconHeight,
+            src: o.src
+        });
+        if (BI.isNumber(o.iconWidth) || BI.isNumber(o.iconHeight)) {
+            BI.createWidget({
+                type: "bi.center_adapt",
+                element: this,
+                items: [this.image]
+            })
+        } else {
+            BI.createWidget({
+                type: "bi.adaptive",
+                element: this,
+                items: [this.image],
+                scrollable: false
+            })
+        }
+    },
+
+    setWidth: function (w) {
+        BI.ImageButton.superclass.setWidth.apply(this, arguments);
+        this.options.width = w;
+    },
+
+    setHeight: function (h) {
+        BI.ImageButton.superclass.setHeight.apply(this, arguments);
+        this.options.height = h;
+    },
+
+    setImageWidth: function (w) {
+        this.image.setWidth(w);
+    },
+
+    setImageHeight: function (h) {
+        this.image.setHeight(h);
+    },
+
+    getImageWidth: function () {
+        return this.image.element.width();
+    },
+
+    getImageHeight: function () {
+        return this.image.element.height();
+    },
+
+    setSrc: function (src) {
+        this.options.src = src;
+        this.image.setSrc(src);
+    },
+
+    getSrc: function () {
+        return this.image.getSrc();
+    },
+
+    doClick: function () {
+        BI.ImageButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.ImageButton.EVENT_CHANGE, this);
+        }
+    }
+});
+BI.ImageButton.EVENT_CHANGE = "ImageButton.EVENT_CHANGE";
+$.shortcut("bi.image_button", BI.ImageButton);(function ($) {
+
+    /**
+     * 文字类型的按钮
+     * @class BI.Button
+     * @extends BI.BasicButton
+     *
+     * @cfg {JSON} options 配置属性
+     * @cfg {'common'/'success'/'warning'/'ignore'} [options.level='common'] 按钮类型,用不同颜色强调不同的场景
+     */
+    BI.Button = BI.inherit(BI.BasicButton, {
+        _const: {
+            minWidth: 90
+        },
+
+        _defaultConfig: function () {
+            var conf = BI.Button.superclass._defaultConfig.apply(this, arguments);
+            return BI.extend(conf, {
+                baseCls: (conf.baseCls || "") + ' bi-button',
+                shadow: true,
+                isShadowShowingOnSelected: true,
+                readonly: true,
+                iconClass: "",
+                level: 'common',
+                textAlign: "center",
+                whiteSpace: "nowrap",
+                forceCenter: false,
+                textWidth: null,
+                textHeight: null,
+                hgap: 10,
+                vgap: 0,
+                tgap: 0,
+                bgap: 0,
+                lgap: 0,
+                rgap: 0
+            })
+        },
+
+        _init: function () {
+            BI.Button.superclass._init.apply(this, arguments);
+            var o = this.options, self = this;
+            if (BI.isNumber(o.height)) {
+                this.element.css({height: o.height - 2, lineHeight: (o.height - 2) + 'px'});
+            }
+            if (BI.isKey(o.iconClass)) {
+                this.icon = BI.createWidget({
+                    type: "bi.icon",
+                    width: 18
+                });
+                this.text = BI.createWidget({
+                    type: "bi.label",
+                    text: o.text,
+                    value: o.value
+                });
+                BI.createWidget({
+                    type: "bi.horizontal_auto",
+                    cls: "button-" + o.level + " " + o.iconClass,
+                    element: this,
+                    hgap: o.hgap,
+                    vgap: o.vgap,
+                    tgap: o.tgap,
+                    bgap: o.bgap,
+                    lgap: o.lgap,
+                    rgap: o.rgap,
+                    items: [{
+                        type: "bi.horizontal",
+                        items: [this.icon, this.text]
+                    }]
+                })
+            } else {
+                this.text = BI.createWidget({
+                    type: "bi.label",
+                    cls: "button-" + o.level,
+                    textAlign: o.textAlign,
+                    whiteSpace: o.whiteSpace,
+                    forceCenter: o.forceCenter,
+                    textWidth: o.textWidth,
+                    textHeight: o.textHeight,
+                    hgap: o.hgap,
+                    vgap: o.vgap,
+                    tgap: o.tgap,
+                    bgap: o.bgap,
+                    lgap: o.lgap,
+                    rgap: o.rgap,
+                    element: this,
+                    text: o.text,
+                    value: o.value
+                });
+            }
+            this.element.css({"min-width": this._const.minWidth - 2 + "px"});
+        },
+
+        doClick: function () {
+            BI.Button.superclass.doClick.apply(this, arguments);
+            if (this.isValid()) {
+                this.fireEvent(BI.Button.EVENT_CHANGE, this);
+            }
+        },
+
+        setText: function (text) {
+            BI.Button.superclass.setText.apply(this, arguments);
+            this.text.setText(text);
+        },
+
+        setValue: function (text) {
+            BI.Button.superclass.setValue.apply(this, arguments);
+            if (!this.isReadOnly()) {
+                this.text.setValue(text);
+            }
+        },
+
+        setEnable: function (b) {
+            BI.Button.superclass.setEnable.apply(this, arguments);
+            this.text.setEnable(b);
+            this.icon && this.icon.setEnable(b);
+        },
+
+        doRedMark: function () {
+            this.text.doRedMark.apply(this.text, arguments);
+        },
+
+        unRedMark: function () {
+            this.text.unRedMark.apply(this.text, arguments);
+        },
+
+        doHighLight: function () {
+            this.text.doHighLight.apply(this.text, arguments);
+        },
+
+        unHighLight: function () {
+            this.text.unHighLight.apply(this.text, arguments);
+        },
+
+        destroy: function () {
+            BI.Button.superclass.destroy.apply(this, arguments);
+        }
+    });
+    $.shortcut('bi.button', BI.Button);
+    BI.Button.EVENT_CHANGE = "EVENT_CHANGE";
+})(jQuery);/**
+ * guy
+ * 可以点击的一行文字
+ * @class BI.TextButton
+ * @extends BI.BasicButton
+ * 文字button
+ */
+BI.TextButton = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function() {
+        var conf = BI.TextButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            tagName: "a",
+            baseCls: (conf.baseCls || "") + " bi-text-button display-block",
+            textAlign: "center",
+            whiteSpace: "nowrap",
+            forceCenter: false,
+            textWidth: null,
+            textHeight: null,
+            hgap: 0,
+            lgap: 0,
+            rgap: 0,
+            text:"",
+            py: ""
+        })
+    },
+
+    _init:function() {
+        BI.TextButton.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: o.textAlign,
+            whiteSpace: o.whiteSpace,
+            textWidth: o.textWidth,
+            textHeight: o.textHeight,
+            forceCenter: o.forceCenter,
+            width: o.width,
+            height: o.height,
+            hgap: o.hgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+    },
+
+    doClick: function(){
+        BI.TextButton.superclass.doClick.apply(this, arguments);
+        if(this.isValid()) {
+            this.fireEvent(BI.TextButton.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function(){
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function(){
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setText: function(text){
+        BI.TextButton.superclass.setText.apply(this, arguments);
+        text = BI.isArray(text) ? text.join(",") : text;
+        this.text.setText(text);
+    },
+
+    setValue: function(text){
+        BI.TextButton.superclass.setValue.apply(this, arguments);
+        if(!this.isReadOnly()) {
+            text = BI.isArray(text) ? text.join(",") : text;
+            this.text.setValue(text);
+        }
+    }
+});
+BI.TextButton.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_button", BI.TextButton);/**
+ * guy
+ * 一个占位符和两个icon和一行数 组成的一行listitem
+ *
+ * Created by GUY on 2015/9/15.
+ * @class BI.BlankIconTextIconItem
+ * @extends BI.BasicButton
+ */
+BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.BlankIconTextIconItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-blank-icon-text-icon-item",
+            logic: {
+                dynamic: false
+            },
+            iconCls1: "close-ha-font",
+            iconCls2: "close-ha-font",
+            blankWidth: 0,
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.BlankIconTextIconItem.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+
+        var icon1 = BI.createWidget({
+            type: "bi.center_adapt",
+            cls: o.iconCls1,
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.center_adapt",
+                    cls: o.iconCls2,
+                    width: c.commonWidth,
+                    items: [{
+                        el: {
+                            type: "bi.icon",
+                            width: o.iconWidth,
+                            height: o.iconHeight
+                        }
+                    }]
+                },
+                top: 0,
+                bottom: 0,
+                right: 0
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", {
+                type: "bi.layout",
+                width: o.blankWidth
+            }, icon1, this.text, {
+                type: "bi.layout",
+                width: c.commonWidth
+            })
+        }))));
+    },
+
+    doClick: function () {
+        BI.BlankIconTextIconItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.BlankIconTextIconItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    }
+});
+BI.BlankIconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.blank_icon_text_icon_item", BI.BlankIconTextIconItem);/**
+ * 带有一个占位
+ *
+ * Created by GUY on 2015/9/11.
+ * @class BI.BlankIconTextItem
+ * @extends BI.BasicButton
+ */
+BI.BlankIconTextItem = BI.inherit(BI.BasicButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.BlankIconTextItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-blank-icon-text-item",
+            logic: {
+                dynamic: false
+            },
+            cls: "close-ha-font",
+            blankWidth: 0,
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.BlankIconTextItem.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        var blank = BI.createWidget({
+            type: "bi.layout",
+            width: o.blankWidth
+        })
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+        this.icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", blank, this.icon, this.text)
+        }))));
+    },
+
+    doClick: function () {
+        BI.BlankIconTextItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.BlankIconTextItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    }
+});
+BI.BlankIconTextItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.blank_icon_text_item", BI.BlankIconTextItem);/**
+ * guy
+ * 两个icon和一行数 组成的一行listitem
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.IconTextIconItem
+ * @extends BI.BasicButton
+ */
+BI.IconTextIconItem = BI.inherit(BI.BasicButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.IconTextIconItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-icon-text-icon-item",
+            logic: {
+                dynamic: false
+            },
+            iconCls1: "close-ha-font",
+            iconCls2: "close-ha-font",
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.IconTextIconItem.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+
+        var icon1 = BI.createWidget({
+            type: "bi.center_adapt",
+            cls: o.iconCls1,
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        })
+        var blank = BI.createWidget({
+            type: "bi.layout",
+            width: c.commonWidth
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.center_adapt",
+                    cls: o.iconCls2,
+                    width: c.commonWidth,
+                    items: [{
+                        el: {
+                            type: "bi.icon",
+                            width: o.iconWidth,
+                            height: o.iconHeight
+                        }
+                    }]
+                },
+                top: 0,
+                bottom: 0,
+                right: 0
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", icon1, this.text, blank)
+        }))));
+    },
+
+    doClick: function () {
+        BI.IconTextIconItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.IconTextIconItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    }
+});
+BI.IconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_text_icon_item", BI.IconTextIconItem);/**
+ * guy
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.IconTextItem
+ * @extends BI.BasicButton
+ */
+BI.IconTextItem = BI.inherit(BI.BasicButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.IconTextItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-icon-text-item",
+            direction: BI.Direction.Left,
+            logic: {
+                dynamic: false
+            },
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.IconTextItem.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        });
+        this.icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.icon, this.text)
+        }))));
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    },
+
+    doClick: function () {
+        BI.IconTextItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.IconTextItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    }
+});
+BI.IconTextItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_text_item", BI.IconTextItem);/**
+ *
+ * 图标的button
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.TextIconItem
+ * @extends BI.BasicButton
+ */
+BI.TextIconItem = BI.inherit(BI.BasicButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.TextIconItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-icon-item",
+            logic: {
+                dynamic: false
+            },
+            cls: "close-ha-font",
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.TextIconItem.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        });
+        this.icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", this.text, this.icon)
+        }))));
+    },
+
+    doClick: function () {
+        BI.TextIconItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.TextIconItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    }
+});
+BI.TextIconItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_icon_item", BI.TextIconItem);/**
+ * guy
+ * 一个button和一行数 组成的一行listitem
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.TextItem
+ * @extends BI.BasicButton
+ */
+BI.TextItem = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.TextItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-item",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.TextItem.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: o.textAlign,
+            whiteSpace: o.whiteSpace,
+            textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight,
+            height: o.height,
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            py: o.py
+        });
+    },
+
+    doClick: function () {
+        BI.TextItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.TextItem.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    }
+});
+BI.TextItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_item", BI.TextItem);/**
+ * guy
+ * Created by GUY on 2015/9/9.
+ * @class BI.IconTextIconNode
+ * @extends BI.NodeButton
+ */
+BI.IconTextIconNode = BI.inherit(BI.NodeButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.IconTextIconNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-icon-text-icon-node",
+            logic: {
+                dynamic: false
+            },
+            iconCls1: "close-ha-font",
+            iconCls2: "close-ha-font",
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.IconTextIconNode.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+
+        var icon1 = BI.createWidget({
+            type: "bi.center_adapt",
+            cls: o.iconCls1,
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        })
+        var blank = BI.createWidget({
+            type: "bi.layout",
+            width: c.commonWidth
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.center_adapt",
+                    cls: o.iconCls2,
+                    width: c.commonWidth,
+                    items: [{
+                        el: {
+                            type: "bi.icon",
+                            width: o.iconWidth,
+                            height: o.iconHeight
+                        }
+                    }]
+                },
+                top: 0,
+                bottom: 0,
+                right: 0
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", icon1, this.text, blank)
+        }))));
+    },
+
+    doClick: function () {
+        BI.IconTextIconNode.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.IconTextIconNode.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    }
+});
+BI.IconTextIconNode.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_text_icon_node", BI.IconTextIconNode);/**
+ * guy
+ * Created by GUY on 2015/9/9.
+ * @class BI.IconTextNode
+ * @extends BI.NodeButton
+ */
+BI.IconTextNode = BI.inherit(BI.NodeButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.IconTextNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-icon-text-node",
+            logic: {
+                dynamic: false
+            },
+            cls: "close-ha-font",
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.IconTextNode.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+        this.icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon, this.text)
+        }))));
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    },
+
+    doClick: function () {
+        BI.IconTextNode.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.IconTextNode.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    }
+});
+BI.IconTextNode.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_text_node", BI.IconTextNode);/**
+ * Created by GUY on 2015/9/9.
+ * @class BI.TextIconNode
+ * @extends BI.NodeButton
+ */
+BI.TextIconNode = BI.inherit(BI.NodeButton, {
+    _const: {
+        commonWidth: 25
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.TextIconNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-icon-node",
+            logic: {
+                dynamic: false
+            },
+            cls: "close-ha-font",
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.TextIconNode.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height
+        })
+        this.icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: c.commonWidth,
+            items: [{
+                el: {
+                    type: "bi.icon",
+                    width: o.iconWidth,
+                    height: o.iconHeight
+                }
+            }]
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", this.text, this.icon)
+        }))));
+    },
+
+    doClick: function () {
+        BI.TextIconNode.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.TextIconNode.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    }
+});
+BI.TextIconNode.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_icon_node", BI.TextIconNode);/**
+ * guy
+ *
+ * Created by GUY on 2015/9/9.
+ * @class BI.TextNode
+ * @extends BI.NodeButton
+ */
+BI.TextNode = BI.inherit(BI.NodeButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.TextNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-node",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.TextNode.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: o.textAlign,
+            whiteSpace: o.whiteSpace,
+            textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight,
+            height: o.height,
+            hgap: o.textHgap,
+            vgap: o.textVgap,
+            lgap: o.textLgap,
+            rgap: o.textRgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            py: o.py
+        });
+    },
+
+    doClick: function () {
+        BI.TextNode.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.TextNode.EVENT_CHANGE, this.getValue(), this);
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    setValue: function () {
+        if (!this.isReadOnly()) {
+            this.text.setValue.apply(this.text, arguments);
+        }
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    },
+
+    setText: function () {
+        this.text.setText.apply(this.text, arguments);
+    },
+
+    getText: function () {
+        return this.text.getText();
+    }
+});
+BI.TextNode.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_node", BI.TextNode);/**
+ *
+ * Created by GUY on 2016/1/15.
+ * @class BI.CodeEditor
+ * @extends BI.Single
+ */
+BI.CodeEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return $.extend(BI.CodeEditor.superclass._defaultConfig.apply(), {
+            baseCls: 'bi-code-editor',
+            value: '',
+            watermark: ""
+        });
+    },
+    _init: function () {
+        BI.CodeEditor.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.editor = CodeMirror(this.element[0], {
+            textWrapping: true,
+            lineWrapping: true,
+            lineNumbers: false
+        });
+        this.editor.on("change", function (cm, change) {
+            BI.nextTick(function () {
+                self.fireEvent(BI.CodeEditor.EVENT_CHANGE)
+            });
+        });
+
+        this.editor.on("focus", function () {
+            watermark.setVisible(false);
+            self.fireEvent(BI.CodeEditor.EVENT_FOCUS);
+        });
+
+        this.editor.on("blur", function () {
+            watermark.setVisible(BI.isEmptyString(self.getValue()));
+            self.fireEvent(BI.CodeEditor.EVENT_BLUR);
+        });
+
+        // this.editor.on("blur", function () {
+        //     self.editor.execCommand("goLineEnd");
+        // });
+
+        //水印
+        var watermark = BI.createWidget({
+            type: "bi.label",
+            text: o.watermark,
+            cls: "bi-water-mark",
+            whiteSpace: "nowrap",
+            textAlign: "left"
+        });
+        watermark.element.bind(
+            "mousedown", function (e) {
+                self.insertString("");
+                self.editor.focus();
+                e.stopEvent();
+            }
+        );
+        watermark.element.bind("click", function (e) {
+            self.editor.focus();
+            e.stopEvent();
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: watermark,
+                top: 0,
+                left: 5
+            }]
+        });
+
+        if (BI.isKey(o.value)) {
+            BI.nextTick(function () {
+                self.setValue(o.value);
+            });
+        }
+    },
+
+    setEnable: function (b) {
+        BI.CodeEditor.superclass.setEnable.apply(this, arguments);
+        this.editor.setOption("readOnly", b === true ? false : "nocursor")
+    },
+
+    insertParam: function(param){
+        var from = this.editor.getCursor();
+        this.editor.replaceSelection(param);
+        var to = this.editor.getCursor();
+        this.editor.markText(from, to, {className: 'param', atomic: true});
+        this.editor.replaceSelection(" ");
+        this.editor.focus();
+    },
+
+    insertString: function(str){
+        this.editor.replaceSelection(str);
+        this.editor.focus();
+    },
+
+    getValue: function () {
+        return this.editor.getValue("\n", function (line) {
+            var rawText = line.text, value = line.text, num = 0;
+            value.text = rawText;
+            _.forEach(line.markedSpans, function (i, ms) {
+                switch (i.marker.className) {
+                    case "param":
+                        var fieldNameLength = i.to - i.from;
+                        value = value.substr(0, i.from + num) + "$\{" + value.substr(i.from + num, fieldNameLength) + "\}" + value.substr(i.to + num, value.length);
+                        num += fieldNameLength + 3;
+                        break;
+                }
+            });
+            return value;
+        });
+    },
+
+    _analyzeContent: function (v) {
+        var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)|\n/g;
+        return v.match(regx);
+    },
+
+    setValue: function (v) {
+        var self = this, result;
+        this.refresh();
+        self.editor.setValue("");
+        result = this._analyzeContent(v || "");
+        BI.each(result, function (i, item) {
+            var fieldRegx = /\$[\{][^\}]*[\}]/;
+            var str = item.match(fieldRegx);
+            if (BI.isNotEmptyArray(str)) {
+                self.insertParam(str[0].substring(2, item.length - 1));
+            } else {
+                self.insertString(item);
+            }
+        })
+    },
+
+    refresh: function(){
+        var self = this;
+        BI.nextTick(function () {
+            self.editor.refresh();
+        });
+    }
+});
+BI.CodeEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.CodeEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.CodeEditor.EVENT_FOCUS = "EVENT_FOCUS";
+$.shortcut("bi.code_editor", BI.CodeEditor);/**
+ * Created by GUY on 2015/4/15.
+ * @class BI.Editor
+ * @extends BI.Single
+ */
+BI.Editor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Editor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            tipType: "warning",
+            inputType: "text",
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: false,
+            watermark: "",
+            errorText: ""
+        })
+    },
+
+    _init: function () {
+        BI.Editor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = this.addWidget(BI.createWidget({
+            type: "bi.input",
+            element: "<input type='" + o.inputType + "'/>",
+            watermark: o.watermark,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank
+        }));
+        this.editor.element.css({
+            "width": "100%",
+            "height": "100%",
+            "border": "none",
+            "outline": "none",
+            "padding": "0",
+            "margin": "0"
+        });
+        if (BI.isKey(this.options.watermark)) {
+            this.watermark = BI.createWidget({
+                type: "bi.label",
+                cls: "bi-water-mark",
+                text: this.options.watermark,
+                forceCenter: true,
+                whiteSpace: "nowrap",
+                textAlign: "left"
+            });
+            this.watermark.element.bind({
+                mousedown: function (e) {
+                    if (self.isEnabled()) {
+                        self.editor.isEditing() || self.editor.focus();
+                    } else {
+                        self.editor.isEditing() && self.editor.blur();
+                    }
+                    e.stopEvent();
+                }
+            });
+            this.watermark.element.bind("click", function (e) {
+                if (self.isEnabled()) {
+                    self.editor.isEditing() || self.editor.focus();
+                } else {
+                    self.editor.isEditing() && self.editor.blur();
+                }
+                e.stopEvent();
+            });
+            this.watermark.element.css({
+                position: "absolute",
+                left: "3px",
+                right: "3px",
+                top: "0px",
+                bottom: "0px"
+            });
+        }
+        var items = [{
+            el: {
+                type: "bi.default",
+                items: this.watermark ? [this.editor, this.watermark] : [this.editor]
+            },
+            left: o.hgap + o.lgap,
+            right: o.hgap + o.rgap,
+            top: o.vgap + o.tgap,
+            bottom: o.vgap + o.bgap
+        }];
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: items
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_FOCUS, function () {
+            self._checkError();
+            self.element.addClass("bi-editor-focus");
+            self.fireEvent(BI.Editor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_BLUR, function () {
+            self.setErrorVisible(false);
+            self.element.removeClass("bi-editor-focus");
+            self.fireEvent(BI.Editor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_CLICK, function () {
+            self.fireEvent(BI.Editor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Editor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.Editor.EVENT_KEY_DOWN, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_QUICK_DOWN, function (v) {
+            self.watermark && self.watermark.invisible();
+        });
+
+        this.editor.on(BI.Input.EVENT_VALID, function () {
+            self._checkWaterMark();
+            self.setErrorVisible(false);
+            self.fireEvent(BI.Editor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_ERROR, function () {
+            self._checkWaterMark();
+            self.fireEvent(BI.Editor.EVENT_ERROR, arguments);
+            self.setErrorVisible(self.isEditing());
+        });
+        this.editor.on(BI.Input.EVENT_RESTRICT, function () {
+            self._checkWaterMark();
+            var tip = self.setErrorVisible(true);
+            tip && tip.element.fadeOut(100, function () {
+                tip.element.fadeIn(100);
+            });
+            self.fireEvent(BI.Editor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_EMPTY, function () {
+            self._checkWaterMark();
+            self.fireEvent(BI.Editor.EVENT_EMPTY, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_ENTER, function () {
+            self.fireEvent(BI.Editor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_SPACE, function () {
+            self.fireEvent(BI.Editor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_BACKSPACE, function () {
+            self.fireEvent(BI.Editor.EVENT_BACKSPACE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_REMOVE, function () {
+            self.fireEvent(BI.Editor.EVENT_REMOVE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_START, function () {
+            self.fireEvent(BI.Editor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_PAUSE, function () {
+            self.fireEvent(BI.Editor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_STOP, function () {
+            self.fireEvent(BI.Editor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Input.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.Editor.EVENT_CONFIRM, arguments);
+        });
+        this.element.click(function (e) {
+            e.stopPropagation();
+            return false;
+        });
+        if (BI.isKey(this.options.value) || BI.isEmptyString(this.options.value)) {
+            this.setValue(this.options.value);
+        } else {
+            this._checkWaterMark();
+        }
+    },
+
+    _checkToolTip: function () {
+        var o = this.options;
+        var errorText = o.errorText;
+        if (BI.isFunction(errorText)) {
+            errorText = errorText(this.editor.getValue());
+        }
+        if (BI.isKey(errorText)) {
+            if (!this.isEnabled() || this.isValid() || (BI.Bubbles.has(this.getName()) && BI.Bubbles.get(this.getName()).isVisible())) {
+                this.setTitle("");
+            } else {
+                this.setTitle(errorText);
+            }
+        }
+    },
+
+    _checkError: function () {
+        this.setErrorVisible(this.isEnabled() && !this.isValid());
+        this._checkToolTip();
+    },
+
+    _checkWaterMark: function () {
+        var o = this.options;
+        if (!this.disabledWarterMark && this.editor.getValue() === "" && BI.isKey(o.watermark)) {
+            this.watermark && this.watermark.visible();
+        } else {
+            this.watermark && this.watermark.invisible();
+        }
+    },
+
+    setErrorText: function (text) {
+        this.options.errorText = text;
+    },
+
+    getErrorText: function () {
+        return this.options.errorText;
+    },
+
+    setErrorVisible: function (b) {
+        var o = this.options;
+        var errorText = o.errorText;
+        if (BI.isFunction(errorText)) {
+            errorText = errorText(this.editor.getValue());
+        }
+        if (!this.disabledError && BI.isKey(errorText)) {
+            BI.Bubbles[b ? "show" : "hide"](this.getName(), errorText, this);
+            this._checkToolTip();
+            return BI.Bubbles.get(this.getName());
+        }
+    },
+
+    disableError: function () {
+        this.disabledError = true;
+        this._checkError();
+    },
+
+    enableError: function () {
+        this.disabledError = false;
+        this._checkError();
+    },
+
+    disableWarterMark: function () {
+        this.disabledWarterMark = true;
+        this._checkWaterMark();
+    },
+
+    enableWarterMark: function () {
+        this.disabledWarterMark = false;
+        this._checkWaterMark();
+    },
+
+    focus: function () {
+        this.element.addClass("text-editor-focus");
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.element.removeClass("text-editor-focus");
+        this.editor.blur();
+    },
+
+    selectAll: function () {
+        this.editor.selectAll();
+    },
+
+    onKeyDown: function (k) {
+        this.editor.onKeyDown(k);
+    },
+
+    setValue: function (v) {
+        BI.Editor.superclass.setValue.apply(this, arguments);
+        this.editor.setValue(v);
+        this._checkError();
+        this._checkWaterMark();
+    },
+
+    getLastValidValue: function () {
+        return BI.trim(this.editor.getLastValidValue());
+    },
+
+    resetLastValidValue: function () {
+        this.editor.resetLastValidValue();
+    },
+
+    getValue: function () {
+        if (!this.isValid()) {
+            return BI.trim(this.editor.getLastValidValue());
+        }
+        return BI.trim(this.editor.getValue());
+    },
+
+    setValid: function (b) {
+        BI.Editor.superclass.setValid.apply(this, arguments);
+        this.editor.setValid(b);
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setEnable: function (b) {
+        BI.Editor.superclass.setEnable.apply(this, arguments);
+        this.editor && this.editor.setEnable(b);
+        this.watermark && this.watermark.setEnable(b);
+    }
+});
+BI.Editor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.Editor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.Editor.EVENT_BLUR = "EVENT_BLUR";
+BI.Editor.EVENT_CLICK = "EVENT_CLICK";
+BI.Editor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.Editor.EVENT_SPACE = "EVENT_SPACE";
+BI.Editor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+
+BI.Editor.EVENT_START = "EVENT_START";
+BI.Editor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.Editor.EVENT_STOP = "EVENT_STOP";
+BI.Editor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.Editor.EVENT_VALID = "EVENT_VALID";
+BI.Editor.EVENT_ERROR = "EVENT_ERROR";
+BI.Editor.EVENT_ENTER = "EVENT_ENTER";
+BI.Editor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.Editor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.Editor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.editor", BI.Editor);/**
+ * 多文件
+ *
+ * Created by GUY on 2016/4/13.
+ * @class BI.MultifileEditor
+ * @extends BI.Single
+ * @abstract
+ */
+BI.MultifileEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.MultifileEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-multifile-editor",
+            multiple: false,
+            maxSize: 1024 * 1024,
+            accept: "",
+            url: ""
+        })
+    },
+
+    _init: function () {
+        var self = this, o = this.options;
+        BI.MultifileEditor.superclass._init.apply(this, arguments);
+        this.file = BI.createWidget({
+            type: "bi.file",
+            cls: "multifile-editor",
+            width: "100%",
+            height: "100%",
+            name: o.name,
+            url: o.url,
+            multiple: o.multiple,
+            accept: o.accept,
+            maxSize: o.maxSize
+        });
+        this.file.on(BI.File.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultifileEditor.EVENT_CHANGE, arguments);
+        });
+        this.file.on(BI.File.EVENT_UPLOADSTART, function () {
+            self.fireEvent(BI.MultifileEditor.EVENT_UPLOADSTART, arguments);
+        });
+        this.file.on(BI.File.EVENT_ERROR, function () {
+            self.fireEvent(BI.MultifileEditor.EVENT_ERROR, arguments);
+        });
+        this.file.on(BI.File.EVENT_PROGRESS, function () {
+            self.fireEvent(BI.MultifileEditor.EVENT_PROGRESS, arguments);
+        });
+        this.file.on(BI.File.EVENT_UPLOADED, function () {
+            self.fireEvent(BI.MultifileEditor.EVENT_UPLOADED, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.adaptive",
+                    scrollable: false,
+                    items: [this.file]
+                },
+                top: 0,
+                right: 0,
+                left: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    select: function () {
+        this.file.select();
+    },
+
+    getValue: function () {
+        return this.file.getValue();
+    },
+
+    upload: function () {
+        this.file.upload();
+    },
+
+    reset: function () {
+        this.file.reset();
+    },
+
+    setEnable: function (enable) {
+        BI.MultiFile.superclass.setEnable.apply(this, arguments);
+        this.file.setEnable(enable);
+    }
+});
+BI.MultifileEditor.EVENT_CHANGE = "MultifileEditor.EVENT_CHANGE";
+BI.MultifileEditor.EVENT_UPLOADSTART = "MultifileEditor.EVENT_UPLOADSTART";
+BI.MultifileEditor.EVENT_ERROR = "MultifileEditor.EVENT_ERROR";
+BI.MultifileEditor.EVENT_PROGRESS = "MultifileEditor.EVENT_PROGRESS";
+BI.MultifileEditor.EVENT_UPLOADED = "MultifileEditor.EVENT_UPLOADED";
+$.shortcut("bi.multifile_editor", BI.MultifileEditor);/**
+ *
+ * Created by GUY on 2016/1/18.
+ * @class BI.TextAreaEditor
+ * @extends BI.Single
+ */
+BI.TextAreaEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return $.extend(BI.TextAreaEditor.superclass._defaultConfig.apply(), {
+            baseCls: 'bi-textarea-editor',
+            value: ''
+        });
+    },
+    _init: function () {
+        BI.TextAreaEditor.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.content = BI.createWidget({
+            type: "bi.layout",
+            tagName: "textarea",
+            width: "100%",
+            height: "100%",
+            cls: "textarea-editor-content display-block"
+        });
+        this.content.element.css({"resize": "none"});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.adaptive",
+                    items: [this.content]
+                },
+                left: 0,
+                right: 3,
+                top: 0,
+                bottom: 5
+            }]
+        });
+
+        this.content.element.focus(function () {
+            self.content.element.addClass("textarea-editor-focus");
+            self.fireEvent(BI.TextAreaEditor.EVENT_FOCUS);
+        });
+        this.content.element.blur(function () {
+            self.content.element.removeClass("textarea-editor-focus");
+            self.fireEvent(BI.TextAreaEditor.EVENT_BLUR);
+        });
+        if (BI.isKey(o.value)) {
+            self.setValue(o.value);
+        }
+    },
+
+    focus: function () {
+        this.content.element.addClass("textarea-editor-focus");
+        this.content.element.focus();
+    },
+
+    blur: function () {
+        this.content.element.removeClass("textarea-editor-focus");
+        this.content.element.blur();
+    },
+
+    getValue: function () {
+        return this.content.element.val();
+    },
+
+    setValue: function (value) {
+        this.content.element.val(value);
+    },
+
+    setStyle: function (style) {
+        this.style = style;
+        this.element.css(style);
+        this.content.element.css(style)
+    },
+
+    getStyle: function () {
+        return this.style;
+    },
+
+    setValid: function (b) {
+        BI.TextAreaEditor.superclass.setValid.apply(this, arguments);
+        this.content.setValid(b);
+    },
+
+    setEnable: function (b) {
+        BI.TextAreaEditor.superclass.setEnable.apply(this, arguments);
+        this.content.setEnable(b);
+    }
+});
+BI.TextAreaEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.TextAreaEditor.EVENT_FOCUS = "EVENT_FOCUS";
+$.shortcut("bi.textarea_editor", BI.TextAreaEditor);/**
+ * guy 图标
+ * @class BI.Icon
+ * @extends BI.Single
+ */
+BI.Icon = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Icon.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            tagName: "i",
+            baseCls: (conf.baseCls || "") + " x-icon b-font horizon-center display-block"
+        })
+    },
+    _init: function () {
+        BI.Icon.superclass._init.apply(this, arguments);
+    }
+});
+$.shortcut("bi.icon", BI.Icon);/**
+ * @class BI.Iframe
+ * @extends BI.Single
+ * @abstract
+ * Created by GameJian on 2016/3/2.
+ */
+BI.Iframe = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Iframe.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-iframe",
+            src: "",
+            width: "100%",
+            height: "100%"
+        })
+    },
+
+    _init: function () {
+        var o = this.options;
+        this.options.element = $("<iframe frameborder='0' src='" + o.src + "'>");
+        BI.Iframe.superclass._init.apply(this, arguments);
+    },
+
+    setSrc: function (src) {
+        this.options.src = src;
+        this.element.attr("src", src);
+    },
+
+    getSrc: function () {
+        return this.options.src;
+    },
+
+    getWidth: function () {
+        return this.options.width
+    },
+
+    getHeight: function () {
+        return this.options.height
+    }
+});
+
+$.shortcut("bi.iframe", BI.Iframe);/**
+ * ͼƬ
+ *
+ * Created by GUY on 2016/1/26.
+ * @class BI.Img
+ * @extends BI.Single
+ * @abstract
+ */
+BI.Img = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Img.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-img",
+            src: "",
+            width: "100%",
+            height: "100%"
+        })
+    },
+
+    _init: function () {
+        var o = this.options;
+        this.options.element = $("<img src='" + o.src + "'>");
+        BI.Img.superclass._init.apply(this, arguments);
+    },
+
+    setSrc: function (src) {
+        this.options.src = src;
+        this.element.attr("src", src);
+    },
+
+    getSrc: function () {
+        return this.options.src;
+    }
+});
+
+$.shortcut("bi.img", BI.Img);/**
+ * guy
+ * @extends BI.Single
+ * @type {*|void|Object}
+ */
+BI.Checkbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        var conf = BI.Checkbox.superclass._defaultConfig.apply(this,arguments);
+        return BI.extend(conf, {
+            tagName: "a",
+            baseCls: (conf.baseCls || "") + " bi-checkbox check-box-icon",
+            selected: false,
+            handler: BI.emptyFn,
+            width: 16,
+            height: 16,
+            iconWidth: 16,
+            iconHeight: 16
+        })
+    },
+
+    _init : function() {
+        BI.Checkbox.superclass._init.apply(this, arguments);
+    },
+
+    doClick: function(){
+        BI.Checkbox.superclass.doClick.apply(this, arguments);
+        if(this.isValid()){
+            this.fireEvent(BI.Checkbox.EVENT_CHANGE);
+        }
+    }
+});
+BI.Checkbox.EVENT_CHANGE = "Checkbox.EVENT_CHANGE";
+
+$.shortcut("bi.checkbox", BI.Checkbox);/**
+ * 文件
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.File
+ * @extends BI.Single
+ * @abstract
+ */
+(function () {
+
+    /**
+     * @description normalize input.files. create if not present, add item method if not present
+     * @param       Object      generated wrap object
+     * @return      Object      the wrap object itself
+     */
+    var F = (function (item) {
+        return function (input) {
+            var files = input.files || [input];
+            if (!files.item)
+                files.item = item;
+            return files;
+        };
+    })(function (i) {
+        return this[i];
+    });
+
+    var event = {
+
+        /**
+         * @description add an event via addEventListener or attachEvent
+         * @param       DOMElement  the element to add event
+         * @param       String      event name without "on" (e.g. "mouseover")
+         * @param       Function    the callback to associate as event
+         * @return      Object      noswfupload.event
+         */
+        add: document.addEventListener ?
+            function (node, name, callback) {
+                node.addEventListener(name, callback, false);
+                return this;
+            } :
+            function (node, name, callback) {
+                node.attachEvent("on" + name, callback);
+                return this;
+            },
+
+        /**
+         * @description remove an event via removeEventListener or detachEvent
+         * @param       DOMElement  the element to remove event
+         * @param       String      event name without "on" (e.g. "mouseover")
+         * @param       Function    the callback associated as event
+         * @return      Object      noswfupload.event
+         */
+        del: document.removeEventListener ?
+            function (node, name, callback) {
+                node.removeEventListener(name, callback, false);
+                return this;
+            } :
+            function (node, name, callback) {
+                node.detachEvent("on" + name, callback);
+                return this;
+            },
+
+        /**
+         * @description to block event propagation and prevent event default
+         * @param       void        generated event or undefined
+         * @return      Boolean     false
+         */
+        stop: function (e) {
+            if (!e) {
+                if (self.event)
+                    event.returnValue = !(event.cancelBubble = true);
+            } else {
+                e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
+                e.preventDefault ? e.preventDefault() : e.returnValue = false;
+            }
+            ;
+            return false;
+        }
+    };
+
+    var sendFile = (function (toString) {
+        var multipart = function (boundary, name, file) {
+                return "--".concat(
+                    boundary, CRLF,
+                    'Content-Disposition: form-data; name="', name, '"; filename="', BI.cjkEncode(file.fileName), '"', CRLF,
+                    "Content-Type: application/octet-stream", CRLF,
+                    CRLF,
+                    file.getAsBinary(), CRLF,
+                    "--", boundary, "--", CRLF
+                );
+            },
+            isFunction = function (Function) {
+                return toString.call(Function) === "[object Function]";
+            },
+            split = "onabort.onerror.onloadstart.onprogress".split("."),
+            length = split.length,
+            CRLF = "\r\n",
+            xhr = this.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP"),
+            sendFile;
+
+        // FireFox 3+, Safari 4 beta (Chrome 2 beta file is buggy and will not work)
+        if (xhr.upload || xhr.sendAsBinary)
+            sendFile = function (handler, maxSize, width, height) {
+                if (-1 < maxSize && maxSize < handler.file.fileSize) {
+                    if (isFunction(handler.onerror))
+                        handler.onerror();
+                    return;
+                }
+                for (var
+                         xhr = new XMLHttpRequest,
+                         upload = xhr.upload || {
+                                 addEventListener: function (event, callback) {
+                                     this["on" + event] = callback
+                                 }
+                             },
+                         i = 0;
+                     i < length;
+                     i++
+                )
+                    upload.addEventListener(
+                        split[i].substring(2),
+                        (function (event) {
+                            return function (rpe) {
+                                if (isFunction(handler[event]))
+                                    handler[event](rpe, xhr);
+                            };
+                        })(split[i]),
+                        false
+                    );
+                upload.addEventListener(
+                    "load",
+                    function (rpe) {
+                        if (handler.onreadystatechange === false) {
+                            if (isFunction(handler.onload))
+                                handler.onload(rpe, xhr);
+                        } else {
+                            setTimeout(function () {
+                                if (xhr.readyState === 4) {
+                                    if (isFunction(handler.onload))
+                                        handler.onload(rpe, xhr);
+                                } else {
+                                    setTimeout(arguments.callee, 15);
+                                }
+                            }, 15);
+                        }
+                    },
+                    false
+                );
+                xhr.open("post", handler.url + '&filename=' + BI.cjkEncode(handler.file.fileName), true);
+                if (!xhr.upload) {
+                    var rpe = {loaded: 0, total: handler.file.fileSize || handler.file.size, simulation: true};
+                    rpe.interval = setInterval(function () {
+                        rpe.loaded += 1024 / 4;
+                        if (rpe.total <= rpe.loaded)
+                            rpe.loaded = rpe.total;
+                        upload.onprogress(rpe);
+                    }, 100);
+                    xhr.onabort = function () {
+                        upload.onabort({});
+                    };
+                    xhr.onerror = function () {
+                        upload.onerror({});
+                    };
+                    xhr.onreadystatechange = function () {
+                        switch (xhr.readyState) {
+                            case    2:
+                            case    3:
+                                if (rpe.total <= rpe.loaded)
+                                    rpe.loaded = rpe.total;
+                                upload.onprogress(rpe);
+                                break;
+                            case    4:
+                                clearInterval(rpe.interval);
+                                rpe.interval = 0;
+                                rpe.loaded = rpe.total;
+                                upload.onprogress(rpe);
+                                if (199 < xhr.status && xhr.status < 400) {
+                                    upload["onload"]({});
+                                    var attachO = BI.jsonDecode(xhr.responseText);
+                                    attachO.filename = BI.cjkDecode(handler.file.fileName);
+                                    if (handler.file.type.indexOf('image') != -1) {
+                                        attachO.attach_type = "image";
+                                    }
+                                    handler.attach_array.push(attachO);
+                                } else {
+                                    upload["onerror"]({});
+                                }
+                                break;
+                        }
+                    };
+                    upload.onloadstart(rpe);
+                } else {
+                    xhr.onreadystatechange = function () {
+                        switch (xhr.readyState) {
+                            case    4:
+                                var attachO = BI.jsonDecode(xhr.responseText);
+                                if (handler.file.type.indexOf('image') != -1) {
+                                    attachO.attach_type = "image";
+                                }
+                                attachO.filename = BI.cjkDecode(handler.file.fileName);
+                                if (handler.maxlength == 1) {
+                                    handler.attach_array[0] = attachO;
+                                    //                                   handler.attach_array.push(attachO);
+                                } else {
+                                    handler.attach_array.push(attachO);
+                                }
+                                break;
+                        }
+                    }
+                }
+                var boundary = "AjaxUploadBoundary" + (new Date).getTime();
+                xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
+                if (handler.file.getAsBinary) {
+                    xhr[xhr.sendAsBinary ? "sendAsBinary" : "send"](multipart(boundary, handler.name, handler.file));
+                } else {
+                    xhr.setRequestHeader("Content-Type", "multipart/form-data");
+//                    xhr.setRequestHeader("X-Name", handler.name);
+//                    xhr.setRequestHeader("X-File-Name", handler.file.fileName);
+                    var form = new FormData();
+                    form.append("FileData", handler.file);
+                    xhr.send(form);
+                }
+                return handler;
+            };
+        // Internet Explorer, Opera, others
+        else
+            sendFile = function (handler, maxSize, width, height) {
+                var url = handler.url.concat(-1 === handler.url.indexOf("?") ? "?" : "&", "AjaxUploadFrame=true"),
+                    rpe = {
+                        loaded: 1, total: 100, simulation: true, interval: setInterval(function () {
+                            if (rpe.loaded < rpe.total)
+                                ++rpe.loaded;
+                            if (isFunction(handler.onprogress))
+                                handler.onprogress(rpe, {});
+                        }, 100)
+                    },
+                    onload = function () {
+                        iframe.onreadystatechange = iframe.onload = iframe.onerror = null;
+                        form.parentNode.removeChild(form);
+                        form = null;
+                        clearInterval(rpe.interval);
+                        //rpe.loaded = rpe.total;
+                        try {
+                            var responseText = (iframe.contentWindow.document || iframe.contentWindow.contentDocument).body.innerHTML;
+                            var attachO = BI.jsonDecode(responseText);
+                            if (handler.file.type.indexOf('image') != -1) {
+                                attachO.attach_type = "image";
+                            }
+
+                            //attachO.fileSize = responseText.length;
+                            attachO.filename = BI.cjkDecode(handler.file.fileName);
+                            if (handler.maxlength == 1) {
+                                handler.attach_array[0] = attachO;
+                            } else {
+                                handler.attach_array.push(attachO);
+                            }
+                        } catch (e) {
+                            if (isFunction(handler.onerror))
+                                handler.onerror(rpe, event || window.event);
+                        }
+                        if (isFunction(handler.onload))
+                            handler.onload(rpe, {responseText: responseText});
+                    },
+                    target = ["AjaxUpload", (new Date).getTime(), String(Math.random()).substring(2)].join("_");
+                try { // IE < 8 does not accept enctype attribute ...
+                    var form = document.createElement('<form enctype="multipart/form-data"></form>'),
+                        iframe = handler.iframe || (handler.iframe = document.createElement('<iframe id="' + target + '" name="' + target + '" src="' + url + '"></iframe>'));
+                } catch (e) {
+                    var form = document.createElement('form'),
+                        iframe = handler.iframe || (handler.iframe = document.createElement("iframe"));
+                    form.setAttribute("enctype", "multipart/form-data");
+                    iframe.setAttribute("name", iframe.id = target);
+                    iframe.setAttribute("src", url);
+                }
+                ;
+                iframe.style.position = "absolute";
+                iframe.style.left = iframe.style.top = "-10000px";
+                iframe.onload = onload;
+                iframe.onerror = function (event) {
+                    if (isFunction(handler.onerror))
+                        handler.onerror(rpe, event || window.event);
+                };
+                iframe.onreadystatechange = function () {
+                    if (/loaded|complete/i.test(iframe.readyState)) {
+                        onload();
+
+                        //wei : todo,将附件信息放到handler.attach
+                    }
+                    else if (isFunction(handler.onloadprogress)) {
+                        if (rpe.loaded < rpe.total)
+                            ++rpe.loaded;
+                        handler.onloadprogress(rpe, {
+                            readyState: {
+                                loading: 2,
+                                interactive: 3,
+                                loaded: 4,
+                                complete: 4
+                            }[iframe.readyState] || 1
+                        });
+                    }
+                };
+                form.setAttribute("action", handler.url + '&width=' + width + '&height=' + height);
+                form.setAttribute("target", iframe.id);
+                form.setAttribute("method", "post");
+                form.appendChild(handler.file);
+                form.style.display = "none";
+                if (isFunction(handler.onloadstart))
+                    handler.onloadstart(rpe, {});
+                with (document.body || document.documentElement) {
+                    appendChild(iframe);
+                    appendChild(form);
+                    form.submit();
+                }
+                ;
+                return handler;
+            };
+        xhr = null;
+        return sendFile;
+    })(Object.prototype.toString);
+
+    var sendFiles = function (handler, maxSize, width, height) {
+
+        var length = handler.files.length,
+            i = 0,
+            onload = handler.onload,
+            onloadstart = handler.onloadstart;
+        handler.current = 0;
+        handler.total = 0;
+        handler.sent = 0;
+        while (handler.current < length) {
+            handler.total += (handler.files[handler.current].fileSize || handler.files[handler.current].size);
+            handler.current++;
+        }
+        handler.current = 0;
+        if (length && handler.files[0].fileSize !== -1) {
+            handler.file = handler.files[handler.current];
+
+            sendFile(handler, maxSize, width, height).onload = function (rpe, xhr) {
+                handler.onloadstart = null;
+                handler.sent += (handler.files[handler.current].fileSize || handler.files[handler.current].size);
+                if (++handler.current < length) {
+                    handler.file = handler.files[handler.current];
+                    sendFile(handler, maxSize, width, height).onload = arguments.callee;
+                } else if (onload) {
+                    handler.onloadstart = onloadstart;
+                    handler.onload = onload;
+                    handler.onload(rpe, xhr);
+                }
+            };
+        } else if (length) {
+            handler.total = length * 100;
+            handler.file = handler.files[handler.current];
+            sendFile(handler, maxSize, width, height).onload = function (rpe, xhr) {
+                var callee = arguments.callee;
+                handler.onloadstart = null;
+                handler.sent += 100;
+                if (++handler.current < length) {
+                    if (/\b(chrome|safari)\b/i.test(navigator.userAgent)) {
+                        handler.iframe.parentNode.removeChild(handler.iframe);
+                        handler.iframe = null;
+                    }
+                    ;
+                    setTimeout(function () {
+                        handler.file = handler.files[handler.current];
+                        sendFile(handler, maxSize, width, height).onload = callee;
+                    }, 15);
+                } else if (onload) {
+                    setTimeout(function () {
+                        handler.iframe.parentNode.removeChild(handler.iframe);
+                        handler.iframe = null;
+                        handler.onloadstart = onloadstart;
+                        handler.onload = onload;
+                        handler.onload(rpe, xhr);
+                    }, 15);
+                }
+            };
+        }
+        return handler;
+    };
+
+    BI.File = BI.inherit(BI.Single, {
+        _defaultConfig: function () {
+            var conf = BI.File.superclass._defaultConfig.apply(this, arguments);
+            return BI.extend(conf, {
+                baseCls: (conf.baseCls || "") + " bi-file display-block",
+                element: "<input type='file'>",
+                name: "",
+                url: "",
+                multiple: true,
+                accept: "", /**'*.jpg; *.zip'**/
+                maxSize: 1024 * 1024
+            })
+        },
+
+        _init: function () {
+            var self = this, o = this.options;
+            BI.File.superclass._init.apply(this, arguments);
+            if (o.multiple === true) {
+                this.element.attr("multiple", "multiple");
+            }
+            this.element.attr("name", o.name || this.getName());
+
+            BI.nextTick(function () {
+                // create the noswfupload.wrap Object
+                // wrap.maxSize 文件大小限制
+                // wrap.maxlength 文件个数限制
+                var _wrap = self.wrap = self._wrap(self.element[0], o.maxSize);
+                // fileType could contain whatever text but filter checks *.{extension}
+                // if present
+
+                // handlers
+
+                _wrap.onloadstart = function (rpe, xhr) {
+                    //BI.Msg.toast("loadstart");
+                    self.fireEvent(BI.File.EVENT_UPLOADSTART);
+                };
+
+                _wrap.onprogress = function (rpe, xhr) {
+                    //BI.Msg.toast("onprogress");
+                    // percent for each bar
+
+                    // fileSize is -1 only if browser does not support file info access
+                    // this if splits recent browsers from others
+                    if (this.file.fileSize !== -1) {
+                        // simulation property indicates when the progress event is fake
+                        if (rpe.simulation) {
+
+                        } else {
+
+                        }
+                    } else {
+                        // if fileSIze is -1 browser is using an iframe because it does
+                        // not support
+                        // files sent via Ajax (XMLHttpRequest)
+                        // We can still show some information
+                    }
+                    self.fireEvent(BI.File.EVENT_PROGRESS, {
+                        file: this.file,
+                        total: rpe.total,
+                        loaded: rpe.loaded,
+                        simulation: rpe.simulation
+                    });
+                };
+
+                // generated if there is something wrong during upload
+                _wrap.onerror = function () {
+                    // just inform the user something was wrong
+                    self.fireEvent(BI.File.EVENT_ERROR);
+                };
+
+                // generated when every file has been sent (one or more, it does not
+                // matter)
+                _wrap.onload = function (rpe, xhr) {
+                    var self_ = this;
+                    // just show everything is fine ...
+                    // ... and after a second reset the component
+                    setTimeout(function () {
+                        self_.clean(); // remove files from list
+                        self_.hide(); // hide progress bars and enable input file
+
+                        //BI.Msg.toast("onload");
+                        self.fireEvent(BI.File.EVENT_UPLOADED);
+                        // enable again the submit button/element
+                    }, 1000);
+                };
+                _wrap.url = o.url ? o.url : BI.servletURL
+                + '?op=fr_attach&cmd=ah_upload';
+                _wrap.fileType = o.accept;   //文件类型限制
+                _wrap.attach_array = [];
+                _wrap.attach_names = [];
+                _wrap.attachNum = 0;
+            });
+        },
+
+        _events: function (wrap) {
+            var self = this;
+            event.add(wrap.dom.input, "change", function () {
+                event.del(wrap.dom.input, "change", arguments.callee);
+                for (var input = wrap.dom.input.cloneNode(true), i = 0, files = F(wrap.dom.input); i < files.length; i++) {
+                    var item = files.item(i);
+                    var tempFile = item.value || item.name;
+                    var value = item.fileName || (item.fileName = tempFile.split("\\").pop()),
+                        ext = -1 !== value.indexOf(".") ? value.split(".").pop().toLowerCase() : "unknown",
+                        size = item.fileSize || item.size;
+                    if (wrap.fileType && -1 === wrap.fileType.indexOf("*." + ext)) {
+                        //文件类型不支持
+                        BI.Msg.toast("文件类型不支持");
+                        self.fireEvent(BI.File.EVENT_ERROR, {
+                            errorType: 0,
+                            file: item
+                        });
+                    } else if (wrap.maxSize !== -1 && size && wrap.maxSize < size) {
+                        //文件大小不支持
+                        BI.Msg.toast("文件大小不支持");
+                        self.fireEvent(BI.File.EVENT_ERROR, {
+                            errorType: 1,
+                            file: item
+                        });
+                    } else {
+                        wrap.files.unshift(item);
+                        //BI.Msg.toast(value);
+                        self.fireEvent(BI.File.EVENT_CHANGE, {
+                            file: item
+                        });
+                    }
+                }
+                input.value = "";
+                wrap.dom.input.parentNode.replaceChild(input, wrap.dom.input);
+                wrap.dom.input = input;
+                event.add(wrap.dom.input, "change", arguments.callee);
+            });
+            return wrap;
+        },
+
+        _wrap: function () {
+            var self = this, o = this.options;
+            // be sure input accept multiple files
+            var input = this.element[0];
+            this.element.attr("multiple", "multiple");
+            input.value = "";
+
+            // wrap Object
+            return this._events({
+
+                // DOM namespace
+                dom: {
+                    input: input,        // input file
+                    disabled: false      // internal use, checks input file state
+                },
+                name: input.name,        // name to send for each file ($_FILES[{name}] in the server)
+                                         // maxSize is the maximum amount of bytes for each file
+                maxSize: o.maxSize ? o.maxSize >> 0 : -1,
+                files: [],               // file list
+
+                // remove every file from the noswfupload component
+                clean: function () {
+                    this.files = [];
+                },
+
+                // upload one file a time (which make progress possible rather than all files in one shot)
+                // the handler is an object injected into the wrap one, could be the wrap itself or
+                // something like {onload:function(){alert("OK")},onerror:function(){alert("Error")}, etc ...}
+                upload: function (handler) {
+                    if (handler) {
+                        for (var key in handler)
+                            this[key] = handler[key];
+                    }
+                    sendFiles(this, this.maxSize);
+                    return this;
+                },
+
+                // hide progress bar (total + current) and enable files selection
+                hide: function () {
+                    if (this.dom.disabled) {
+                        this.dom.disabled = false;
+                        this.dom.input.removeAttribute("disabled");
+                    }
+                },
+
+                // show progress bar and disable file selection (used during upload)
+                // total and current are pixels used to style bars
+                // totalProp and currentProp are properties to change, "height" by default
+                show: function (total, current, totalProp, currentProp) {
+                    if (!this.dom.disabled) {
+                        this.dom.disabled = true;
+                        this.dom.input.setAttribute("disabled", "disabled");
+                    }
+                }
+            });
+        },
+
+        select: function () {
+            $(this.wrap.dom.input).click();
+        },
+
+        upload: function (handler) {
+            this.wrap.upload(handler);
+        },
+
+        getValue: function () {
+            return this.wrap.attach_array;
+        },
+
+        reset: function () {
+            this.wrap.attach_array = [];
+            this.wrap.attach_names = [];
+            this.wrap.attachNum = 0;
+        },
+
+        setEnable: function (enable) {
+            BI.MultiFile.superclass.setEnable.apply(this, arguments);
+            if (enable === true) {
+                this.element.attr("disabled", "disabled");
+            } else {
+                this.element.removeAttr("disabled");
+            }
+        }
+    });
+    BI.File.EVENT_CHANGE = "BI.File.EVENT_CHANGE";
+    BI.File.EVENT_UPLOADSTART = "EVENT_UPLOADSTART";
+    BI.File.EVENT_ERROR = "EVENT_ERROR";
+    BI.File.EVENT_PROGRESS = "EVENT_PROGRESS";
+    BI.File.EVENT_UPLOADED = "EVENT_UPLOADED";
+    $.shortcut("bi.file", BI.File);
+})();/**
+ * guy
+ * @class BI.Input 一个button和一行数 组成的一行listitem
+ * @extends BI.Single
+ * @type {*|void|Object}
+ */
+BI.Input = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Input.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-input display-block",
+            element: "<input/>",
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,//按确定键能否退出编辑
+            mouseOut: false,
+            allowBlank: false
+        })
+    },
+
+    _init: function () {
+        BI.Input.superclass._init.apply(this, arguments);
+        var self = this;
+        var _keydown = BI.debounce(function (keyCode) {
+            self.onKeyDown(keyCode);
+            self._keydown_ = false;
+        }, 300);
+        var _clk = BI.debounce(BI.bind(this._click, this), BI.EVENT_RESPONSE_TIME, true);
+        this._blurDebounce = BI.debounce(BI.bind(this._blur, this), BI.EVENT_RESPONSE_TIME, true);
+        this.element
+            .keydown(function (e) {
+                self.fireEvent(BI.Input.EVENT_QUICK_DOWN);
+            })
+            .keyup(function (e) {
+                self._keydown_ = true;
+                _keydown(e.keyCode);
+            })
+            .on("input propertychange", function (e) {
+                self._keydown_ = true;
+                _keydown(e.keyCode);
+            })
+            .click(function (e) {
+                e.stopPropagation();
+                _clk();
+            })
+            .mousedown(function (e) {
+                self.element.val(self.element.val());
+            })
+            .focusout(function (e) {
+                self._blurDebounce();
+            });
+    },
+
+    _focus: function () {
+        this.element.addClass("bi-input-focus");
+        this._checkValidationOnValueChange();
+        this._isEditing = true;
+        if (this.getValue() == "") {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this);
+            this.fireEvent(BI.Input.EVENT_EMPTY);
+        }
+        this.fireEvent(BI.Input.EVENT_FOCUS);
+    },
+
+    _blur: function () {
+        var self = this;
+        if (self._keydown_ === true) {
+            BI.delay(blur, 300);
+        } else {
+            blur();
+        }
+        function blur() {
+            if (!self.isValid() && self.options.quitChecker.apply(self, [BI.trim(self.getValue())]) !== false) {
+                self.element.val(self._lastValidValue ? self._lastValidValue : "");
+                self._checkValidationOnValueChange();
+                self._defaultState();
+            }
+            self.element.removeClass("bi-input-focus");
+            self._isEditing = false;
+            self._start = false;
+            if (self.isValid()) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CONFIRM, self.getValue(), self);
+                self.fireEvent(BI.Input.EVENT_CONFIRM);
+            }
+            self.fireEvent(BI.Input.EVENT_BLUR);
+        }
+    },
+
+    _click: function () {
+        if (this._isEditing !== true) {
+            this._focus();
+            this.selectAll();
+            this.fireEvent(BI.Input.EVENT_CLICK);
+        }
+    },
+
+    onClick: function () {
+        this._click();
+    },
+
+    onKeyDown: function (keyCode) {
+        if (!this.isValid() || BI.trim(this._lastValidValue) !== BI.trim(this.getValue())) {
+            this._checkValidationOnValueChange();
+        }
+        if (keyCode == BI.keyCode.ENTER) {
+            if (this.isValid() || this.options.quitChecker.apply(this, [BI.trim(this.getValue())]) !== false) {
+                this.blur();
+                this.fireEvent(BI.Input.EVENT_ENTER);
+            } else {
+                this.fireEvent(BI.Input.EVENT_RESTRICT);
+            }
+        }
+        if (keyCode == BI.keyCode.SPACE) {
+            this.fireEvent(BI.Input.EVENT_SPACE);
+        }
+        if (keyCode == BI.keyCode.BACKSPACE && this._lastValue == "") {
+            this.fireEvent(BI.Input.EVENT_REMOVE);
+        }
+        if (keyCode == BI.keyCode.BACKSPACE || keyCode == BI.keyCode.DELETE) {
+            this.fireEvent(BI.Input.EVENT_BACKSPACE);
+        }
+        this.fireEvent(BI.Input.EVENT_KEY_DOWN);
+
+        if (this.isValid() && BI.trim(this.getValue()) !== "") {
+            if (BI.trim(this.getValue()) !== this._lastValue && (!this._start || this._lastValue == null || this._lastValue === "")
+                || (this._pause === true && !/(\s|\u00A0)$/.test(this.getValue()))) {
+                this._start = true;
+                this._pause = false;
+                this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STARTEDIT, this.getValue(), this);
+                this.fireEvent(BI.Input.EVENT_START);
+            }
+        }
+
+        if (/(\s|\u00A0)$/.test(this.getValue())) {
+            this._pause = true;
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.PAUSE, "", this);
+            this.fireEvent(BI.Input.EVENT_PAUSE);
+            this._defaultState();
+        } else if ((keyCode === BI.keyCode.BACKSPACE || keyCode === BI.keyCode.DELETE) &&
+            BI.trim(this.getValue()) === "" && (this._lastValue !== null && BI.trim(this._lastValue) !== "")) {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT, this.getValue(), this);
+            this.fireEvent(BI.Input.EVENT_STOP);
+            this._valueChange();
+        } else {
+            this._valueChange();
+        }
+    },
+
+    //初始状态
+    _defaultState: function () {
+        if (this.getValue() == "") {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this);
+            this.fireEvent(BI.Input.EVENT_EMPTY);
+        }
+        this._lastValue = this.getValue();
+        this._lastSubmitValue = null;
+    },
+
+    _valueChange: function () {
+        if (this.isValid() && BI.trim(this.getValue()) !== this._lastSubmitValue) {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CHANGE, this.getValue(), this);
+            this.fireEvent(BI.Input.EVENT_CHANGE);
+            this._lastSubmitValue = BI.trim(this.getValue());
+        }
+        if (this.getValue() == "") {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this);
+            this.fireEvent(BI.Input.EVENT_EMPTY);
+        }
+        this._lastValue = this.getValue();
+    },
+
+    _checkValidationOnValueChange: function () {
+        var o = this.options;
+        var v = this.getValue();
+        this.setValid(
+            (o.allowBlank === true && BI.trim(v) == "") ||
+            (BI.isNotEmptyString(BI.trim(v))
+            && (v === this._lastValidValue ||
+            o.validationChecker.apply(this, [BI.trim(v)]) !== false))
+        );
+    },
+
+    focus: function () {
+        if (!this.element.is(":visible")) {
+            throw new Error("input输入框在不可见下不能focus");
+        }
+        if (!this._isEditing === true) {
+            this.element.focus();
+            this._focus();
+            this.selectAll();
+        }
+    },
+
+    blur: function () {
+        if (!this.element.is(":visible")) {
+            throw new Error("input输入框在不可见下不能blur");
+        }
+        if (this._isEditing === true) {
+            this.element.blur();
+            this._blurDebounce();
+        }
+    },
+
+    selectAll: function () {
+        if (!this.element.is(":visible")) {
+            throw new Error("input输入框在不可见下不能select");
+        }
+        this.element.select();
+        this._isEditing = true;
+    },
+
+    setValue: function (textValue) {
+        this.element.val(textValue);
+        BI.nextTick(BI.bind(function () {
+            this._checkValidationOnValueChange();
+            this._defaultState();
+            if (this.isValid()) {
+                this._lastSubmitValue = this.getValue();
+            }
+        }, this));
+    },
+
+    getValue: function () {
+        return this.element.val() || "";
+    },
+
+    isEditing: function () {
+        return this._isEditing;
+    },
+
+    getLastValidValue: function () {
+        return this._lastValidValue;
+    },
+
+    setValid: function () {
+        BI.Input.superclass.setValid.apply(this, arguments);
+        if (this.isValid()) {
+            this._lastValidValue = this.getValue();
+            this.element.removeClass("bi-input-error");
+            this.fireEvent(BI.Input.EVENT_VALID, BI.trim(this.getValue()), this);
+        } else {
+            if (this._lastValidValue === this.getValue()) {
+                this._lastValidValue = null;
+            }
+            this.element.addClass("bi-input-error");
+            this.fireEvent(BI.Input.EVENT_ERROR, BI.trim(this.getValue()), this);
+        }
+    },
+
+    setEnable: function (b) {
+        BI.Input.superclass.setEnable.apply(this, [b]);
+        this.element[0].disabled = !b;
+    }
+});
+BI.Input.EVENT_CHANGE = "EVENT_CHANGE";
+
+BI.Input.EVENT_FOCUS = "EVENT_FOCUS";
+BI.Input.EVENT_CLICK = "EVENT_CLICK";
+BI.Input.EVENT_BLUR = "EVENT_BLUR";
+BI.Input.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.Input.EVENT_QUICK_DOWN = "EVENT_QUICK_DOWN";
+BI.Input.EVENT_SPACE = "EVENT_SPACE";
+BI.Input.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+
+BI.Input.EVENT_START = "EVENT_START";
+BI.Input.EVENT_PAUSE = "EVENT_PAUSE";
+BI.Input.EVENT_STOP = "EVENT_STOP";
+BI.Input.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.Input.EVENT_REMOVE = "EVENT_REMOVE";
+BI.Input.EVENT_EMPTY = "EVENT_EMPTY";
+BI.Input.EVENT_VALID = "EVENT_VALID";
+BI.Input.EVENT_ERROR = "EVENT_ERROR";
+BI.Input.EVENT_ENTER = "EVENT_ENTER";
+BI.Input.EVENT_RESTRICT = "EVENT_RESTRICT";
+$.shortcut("bi.input", BI.Input);/**
+ * guy
+ * @extends BI.Single
+ * @type {*|void|Object}
+ */
+BI.Radio = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        var conf = BI.Radio.superclass._defaultConfig.apply(this,arguments);
+        return BI.extend(conf, {
+            tagName: "a",
+            baseCls: (conf.baseCls || "") + " bi-radio radio-icon",
+            selected: false,
+            handler: BI.emptyFn,
+            width: 16,
+            height: 16,
+            iconWidth: 16,
+            iconHeight: 16
+        })
+    },
+
+    _init : function() {
+        BI.Radio.superclass._init.apply(this, arguments);
+    },
+
+    doClick: function(){
+        BI.Radio.superclass.doClick.apply(this, arguments);
+        if(this.isValid()){
+            this.fireEvent(BI.Radio.EVENT_CHANGE);
+        }
+    }
+});
+BI.Radio.EVENT_CHANGE = "Radio.EVENT_CHANGE";
+
+$.shortcut("bi.radio", BI.Radio);/**
+ * Created by GUY on 2015/6/26.
+ */
+
+BI.Label = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Label.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-label",
+            textAlign: "center",
+            whiteSpace: "nowrap", //normal  or  nowrap
+            forceCenter: false, //是否无论如何都要居中, 不考虑超出边界的情况, 在未知宽度和高度时有效
+            textWidth: null,
+            textHeight: null,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            text: "",
+            py: "",
+            keyword: ""
+        })
+    },
+
+    _createJson: function () {
+        var o = this.options;
+        return {
+            type: "bi.text",
+            textAlign: o.textAlign,
+            whiteSpace: o.whiteSpace,
+            lineHeight: o.textHeight,
+            text: o.text,
+            value: o.value,
+            py: o.py,
+            keyword: o.keyword
+        };
+    },
+
+    _init: function () {
+        BI.Label.superclass._init.apply(this, arguments);
+
+        if (this.options.textAlign === "center") {
+            this._createCenterEl();
+        } else {
+            this._createNotCenterEl();
+        }
+    },
+
+    _createCenterEl: function () {
+        var o = this.options;
+        var json = this._createJson();
+        if (BI.isNumber(o.width) && o.width > 0) {
+            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
+                if (BI.isNumber(o.height) && o.height > 0) {
+                    var gap = (o.width - o.textWidth) / 2;
+                    BI.createWidget({
+                        type: "bi.adaptive",
+                        height: o.height,
+                        scrollable: true,
+                        element: this,
+                        items: [
+                            {
+                                el: (this.text = BI.createWidget(json)),
+                                left: gap + o.hgap + o.lgap,
+                                right: gap + o.hgap + o.rgap,
+                                top: o.vgap + o.tgap,
+                                bottom: o.vgap + o.bgap
+                            }
+                        ]
+                    });
+                    this.element.css({"line-height": o.height + "px"});
+                    return;
+                }
+                json.width = o.textWidth;
+                BI.createWidget({
+                    type: "bi.center_adapt",
+                    scrollable: true,
+                    element: this,
+                    items: [
+                        {
+                            el: (this.text = BI.createWidget(json))
+                        }
+                    ]
+                });
+                return;
+            }
+            if (o.whiteSpace == "normal") {
+                this.text = BI.createWidget(json);
+                BI.createWidget({
+                    type: "bi.center_adapt",
+                    scrollable: true,
+                    hgap: o.hgap,
+                    vgap: o.vgap,
+                    lgap: o.lgap,
+                    rgap: o.rgap,
+                    tgap: o.tgap,
+                    bgap: o.bgap,
+                    element: this,
+                    items: [this.text]
+                });
+                return;
+            }
+            if (BI.isNumber(o.height) && o.height > 0) {
+                this.element.css({
+                    "line-height": o.height + "px"
+                });
+                BI.createWidget({
+                    type: "bi.absolute",
+                    scrollable: true,
+                    element: this,
+                    items: [{
+                        el: (this.text = BI.createWidget(json)),
+                        left: o.hgap + o.lgap,
+                        right: o.hgap + o.rgap,
+                        top: o.vgap + o.tgap,
+                        bottom: o.vgap + o.bgap
+                    }]
+                });
+                return;
+            }
+            json.width = o.width - 2 * o.hgap;
+            BI.createWidget({
+                type: "bi.center_adapt",
+                scrollable: true,
+                element: this,
+                items: [{
+                    el: (this.text = BI.createWidget(json))
+                }]
+            });
+            return;
+        }
+        if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
+            json.width = o.textWidth;
+            BI.createWidget({
+                type: "bi.center_adapt",
+                scrollable: true,
+                element: this,
+                items: [
+                    {
+                        el: (this.text = BI.createWidget(json))
+                    }
+                ]
+            });
+            return;
+        }
+        if (o.whiteSpace == "normal") {
+            this.text = BI.createWidget(json);
+            this.text = BI.createWidget({
+                type: "bi.center_adapt",
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap,
+                scrollable: true,
+                element: this,
+                items: [this.text]
+            });
+            return;
+        }
+        if (BI.isNumber(o.height) && o.height > 0) {
+            if (BI.isNumber(o.textHeight) && o.textHeight > 0) {
+                this.element.css({
+                    "line-height": o.height + "px"
+                });
+                BI.createWidget({
+                    type: "bi.adaptive",
+                    height: o.height,
+                    scrollable: true,
+                    element: this,
+                    items: [{
+                        el: (this.text = BI.createWidget(json)),
+                        left: o.hgap + o.lgap,
+                        right: o.hgap + o.rgap,
+                        top: o.vgap + o.tgap,
+                        bottom: o.vgap + o.bgap
+                    }]
+                });
+                return;
+            }
+            BI.extend(json, {
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap
+            });
+            this.element.css({
+                "line-height": o.height + "px"
+            });
+            this.text = BI.createWidget(BI.extend(json, {
+                element: this
+            }));
+            BI.createWidget({
+                type: "bi.layout",
+                element: this.text,
+                scrollable: true
+            });
+            return;
+        }
+        BI.extend(json, {
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap
+        });
+        if (o.forceCenter) {
+            this.text = BI.createWidget(json);
+            BI.createWidget({
+                type: "bi.center_adapt",
+                element: this,
+                items: [this.text]
+            });
+            return;
+        }
+        this.text = BI.createWidget(BI.extend(json, {
+            element: this
+        }));
+        BI.createWidget({
+            type: "bi.layout",
+            element: this.text,
+            scrollable: true
+        })
+    },
+
+    _createNotCenterEl: function () {
+        var o = this.options;
+        var json = this._createJson();
+        if (BI.isNumber(o.width) && o.width > 0) {
+            if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
+                if (BI.isNumber(o.height) && o.height > 0) {
+                    BI.createWidget({
+                        type: "bi.adaptive",
+                        height: o.height,
+                        scrollable: true,
+                        element: this,
+                        items: [
+                            {
+                                el: (this.text = BI.createWidget(json)),
+                                left: o.hgap + o.lgap,
+                                right: o.hgap + o.rgap,
+                                top: o.vgap + o.tgap,
+                                bottom: o.vgap + o.bgap
+                            }
+                        ]
+                    });
+                    this.element.css({"line-height": o.height + "px"});
+                    return;
+                }
+                json.width = o.textWidth;
+                BI.createWidget({
+                    type: "bi.vertical_adapt",
+                    scrollable: true,
+                    hgap: o.hgap,
+                    vgap: o.vgap,
+                    lgap: o.lgap,
+                    rgap: o.rgap,
+                    tgap: o.tgap,
+                    bgap: o.bgap,
+                    element: this,
+                    items: [
+                        {
+                            el: (this.text = BI.createWidget(json))
+                        }
+                    ]
+                });
+                return;
+            }
+            if (o.whiteSpace == "normal") {
+                this.text = BI.createWidget(json);
+                BI.createWidget({
+                    type: "bi.vertical_adapt",
+                    scrollable: true,
+                    hgap: o.hgap,
+                    vgap: o.vgap,
+                    lgap: o.lgap,
+                    rgap: o.rgap,
+                    tgap: o.tgap,
+                    bgap: o.bgap,
+                    element: this,
+                    items: [this.text]
+                });
+                return;
+            }
+            if (BI.isNumber(o.height) && o.height > 0) {
+                this.element.css({
+                    "line-height": o.height + "px"
+                });
+                BI.createWidget({
+                    type: "bi.absolute",
+                    scrollable: true,
+                    element: this,
+                    items: [{
+                        el: (this.text = BI.createWidget(json)),
+                        left: o.hgap + o.lgap,
+                        right: o.hgap + o.rgap,
+                        top: o.vgap + o.tgap,
+                        bottom: o.vgap + o.bgap
+                    }]
+                });
+                return;
+            }
+            json.width = o.width - 2 * o.hgap - o.lgap - o.rgap;
+            BI.createWidget({
+                type: "bi.vertical_adapt",
+                scrollable: true,
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap,
+                element: this,
+                items: [{
+                    el: (this.text = BI.createWidget(json))
+                }]
+            });
+            return;
+        }
+        if (BI.isNumber(o.textWidth) && o.textWidth > 0) {
+            json.width = o.textWidth;
+            BI.createWidget({
+                type: "bi.vertical_adapt",
+                scrollable: true,
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap,
+                element: this,
+                items: [
+                    {
+                        el: (this.text = BI.createWidget(json))
+                    }
+                ]
+            });
+            return;
+        }
+        if (o.whiteSpace == "normal") {
+            this.text = BI.createWidget(json)
+            this.text = BI.createWidget({
+                type: "bi.vertical_adapt",
+                scrollable: true,
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap,
+                element: this,
+                items: [this.text]
+            });
+            return;
+        }
+        if (BI.isNumber(o.height) && o.height > 0) {
+            if (BI.isNumber(o.textHeight) && o.textHeight > 0) {
+                this.element.css({
+                    "line-height": o.height + "px"
+                });
+                BI.createWidget({
+                    type: "bi.adaptive",
+                    height: o.height,
+                    scrollable: true,
+                    element: this,
+                    items: [{
+                        el: (this.text = BI.createWidget(json)),
+                        left: o.hgap + o.lgap,
+                        right: o.hgap + o.rgap,
+                        top: o.vgap + o.tgap,
+                        bottom: o.vgap + o.bgap
+                    }]
+                });
+                return;
+            }
+            BI.extend(json, {
+                hgap: o.hgap,
+                vgap: o.vgap,
+                lgap: o.lgap,
+                rgap: o.rgap,
+                tgap: o.tgap,
+                bgap: o.bgap
+            });
+            this.element.css({
+                "line-height": o.height + "px"
+            });
+            this.text = BI.createWidget(BI.extend(json, {
+                element: this
+            }));
+            BI.createWidget({
+                type: "bi.layout",
+                element: this.text,
+                scrollable: true
+            });
+            return;
+        }
+        BI.extend(json, {
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap
+        });
+        if (o.forceCenter) {
+            this.text = BI.createWidget(json);
+            BI.createWidget({
+                type: "bi.vertical_adapt",
+                element: this,
+                items: [this.text]
+            });
+            return;
+        }
+        this.text = BI.createWidget(BI.extend(json, {
+            element: this
+        }));
+        BI.createWidget({
+            type: "bi.layout",
+            element: this.text,
+            scrollable: true
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setText: function (v) {
+        this.options.text = v;
+        this.text.setText(v);
+    },
+
+    getText: function () {
+        return this.options.text;
+    },
+
+    setValue: function (v) {
+        BI.Label.superclass.setValue.apply(this, arguments);
+        if (!this.isReadOnly()) {
+            this.text.setValue(v);
+        }
+    },
+
+    populate: function () {
+        BI.Label.superclass.populate.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.label", BI.Label);/**
+ * guy a元素
+ * @class BI.Link
+ * @extends BI.Text
+ */
+BI.Link = BI.inherit(BI.Label, {
+    _defaultConfig: function() {
+        var conf = BI.Link.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-link",
+            href: "",
+            target: "_blank"
+        })
+    },
+
+    _createJson: function(){
+        var o = this.options;
+        return {
+            type:"bi.a",
+            textAlign: o.textAlign,
+            whiteSpace: o.whiteSpace,
+            lineHeight: o.textHeight,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py,
+            href: o.href,
+            target: o.target
+        };
+    },
+
+    _init : function() {
+        BI.Link.superclass._init.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.link", BI.Link);/**
+ * guy
+ * tip提示
+ * zIndex在10亿级别
+ * @class BI.Tip
+ * @extends BI.Single
+ * @abstract
+ */
+BI.Tip = BI.inherit(BI.Single, {
+    _defaultConfig: function() {
+        var conf = BI.Link.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-tip",
+            zIndex: BI.zIndex_tip
+        })
+    },
+
+    _init : function() {
+        BI.Tip.superclass._init.apply(this, arguments);
+        this.element.css({"zIndex": this.options.zIndex});
+    }
+});/**
+ * 下拉
+ * @class BI.Trigger
+ * @extends BI.Single
+ * @abstract
+ */
+BI.Trigger = BI.inherit(BI.Single, {
+    _defaultConfig: function() {
+        var conf = BI.Trigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-trigger cursor-pointer",
+            height: 30
+        })
+    },
+
+    _init : function() {
+        BI.Trigger.superclass._init.apply(this, arguments);
+    },
+
+    setKey: function(){
+
+    },
+
+    getKey: function(){
+
+    }
+});/**
+ * svg绘图
+ *
+ * Created by GUY on 2015/12/3.
+ * @class BI.Svg
+ * @extends BI.Widget
+ */
+BI.Svg = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Svg.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-svg"
+        })
+    },
+
+    _init: function () {
+        BI.Svg.superclass._init.apply(this, arguments);
+        this.paper = Raphael(this.element[0]);
+
+        $(this.paper.canvas).width("100%").height("100%").css({"left": "0", "top": "0"}).appendTo(this.element);
+
+        this.top = this.paper.top;
+        this.bottom = this.paper.bottom;
+        this.customAttributes = this.paper.customAttributes;
+        this.ca = this.paper.ca;
+        this.raphael = this.paper.raphael;
+    },
+
+    add: function () {
+        return this.paper.add.apply(this.paper, arguments);
+    },
+
+    path: function () {
+        return this.paper.path.apply(this.paper, arguments);
+    },
+
+    image: function () {
+        return this.paper.image.apply(this.paper, arguments);
+    },
+
+    rect: function () {
+        return this.paper.rect.apply(this.paper, arguments);
+    },
+
+    circle: function () {
+        return this.paper.circle.apply(this.paper, arguments);
+    },
+
+    ellipse: function () {
+        return this.paper.ellipse.apply(this.paper, arguments);
+    },
+
+    text: function () {
+        return this.paper.text.apply(this.paper, arguments);
+    },
+
+    print: function () {
+        return this.paper.print.apply(this.paper, arguments);
+    },
+
+
+    setStart: function () {
+        return this.paper.setStart.apply(this.paper, arguments);
+    },
+
+    setFinish: function () {
+        return this.paper.setFinish.apply(this.paper, arguments);
+    },
+
+    setSize: function () {
+        return this.paper.setSize.apply(this.paper, arguments);
+    },
+
+    setViewBox: function () {
+        return this.paper.setViewBox.apply(this.paper, arguments);
+    },
+
+
+    getById: function () {
+        return this.paper.getById.apply(this.paper, arguments);
+    },
+
+    getElementByPoint: function () {
+        return this.paper.getElementByPoint.apply(this.paper, arguments);
+    },
+
+    getElementsByPoint: function () {
+        return this.paper.getElementsByPoint.apply(this.paper, arguments);
+    },
+
+    getFont: function () {
+        return this.paper.getFont.apply(this.paper, arguments);
+    },
+
+
+    set: function () {
+        return this.paper.set.apply(this.paper, arguments);
+    },
+    remove: function () {
+        return this.paper.remove.apply(this.paper, arguments);
+    },
+    clear: function () {
+        return this.paper.clear.apply(this.paper, arguments);
+    }
+});
+$.shortcut("bi.svg", BI.Svg);/**
+ *
+ * 表格
+ *
+ * Created by GUY on 2015/9/22.
+ * @class BI.TableCell
+ * @extends BI.Single
+ */
+BI.TableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-table-cell",
+            textAlign: "left",
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TableCell.superclass._init.apply(this, arguments);
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            whiteSpace: "nowrap",
+            textAlign: this.options.textAlign,
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value,
+            lgap: 5
+        })
+    }
+});
+
+$.shortcut("bi.table_cell", BI.TableCell);/**
+ *
+ * 表格单元格
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.CollectionTableCell
+ * @extends BI.Widget
+ */
+BI.CollectionTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.CollectionTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-collection-table-cell",
+            width: 0,
+            height: 0,
+            _left: 0,
+            _top: 0,
+            cell: {}
+        })
+    },
+
+    _init: function () {
+        BI.CollectionTableCell.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.cell = BI.createWidget(BI.extend({
+            type: "bi.label"
+        }, o.cell, {
+            cls: (o.cell.cls || "") + "collection-table-cell-wrapper",
+            width: o.width - (o._left === 0 ? 1 : 0) - 1,
+            height: o.height - (o._top === 0 ? 1 : 0) - 1
+        }));
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.cell,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    setWidth: function (width) {
+        BI.CollectionTableCell.superclass.setWidth.apply(this, arguments);
+        var o = this.options;
+        this.cell.setWidth(o.width - (o._left === 0 ? 1 : 0) - 1);
+    },
+
+    setHeight: function (height) {
+        BI.CollectionTableCell.superclass.setHeight.apply(this, arguments);
+        var o = this.options;
+        this.cell.setHeight(o.height - (o._top === 0 ? 1 : 0) - 1);
+    }
+});
+
+$.shortcut("bi.collection_table_cell", BI.CollectionTableCell);/**
+ * CollectionTable
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.CollectionTable
+ * @extends BI.Widget
+ */
+BI.CollectionTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.CollectionTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-collection-table",
+            headerRowSize: 25,
+            rowSize: 25,
+            columnSize: [],
+            isNeedFreeze: false,
+            freezeCols: [],
+            isNeedMerge: false,
+            mergeCols: [],
+            mergeRule: BI.emptyFn,
+            header: [],
+            items: [],
+            regionColumnSize: []
+        });
+    },
+
+    _init: function () {
+        BI.CollectionTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._width = 0;
+        this._height = 0;
+        this._scrollBarSize = BI.DOM.getScrollWidth();
+        this.topLeftCollection = BI.createWidget({
+            type: "bi.collection_view",
+            cellSizeAndPositionGetter: function (index) {
+                return self.topLeftItems[index];
+            }
+        });
+        this.topLeftCollection.on(BI.Collection.EVENT_SCROLL, function (scroll) {
+            self.bottomLeftCollection.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.topRightCollection = BI.createWidget({
+            type: "bi.collection_view",
+            cellSizeAndPositionGetter: function (index) {
+                return self.topRightItems[index];
+            }
+        });
+        this.topRightCollection.on(BI.Collection.EVENT_SCROLL, function (scroll) {
+            self.bottomRightCollection.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.bottomLeftCollection = BI.createWidget({
+            type: "bi.collection_view",
+            cellSizeAndPositionGetter: function (index) {
+                return self.bottomLeftItems[index];
+            }
+        });
+        this.bottomLeftCollection.on(BI.Collection.EVENT_SCROLL, function (scroll) {
+            self.bottomRightCollection.setScrollTop(scroll.scrollTop);
+            self.topLeftCollection.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.bottomRightCollection = BI.createWidget({
+            type: "bi.collection_view",
+            cellSizeAndPositionGetter: function (index) {
+                return self.bottomRightItems[index];
+            }
+        });
+        this.bottomRightCollection.on(BI.Collection.EVENT_SCROLL, function (scroll) {
+            self.bottomLeftCollection.setScrollTop(scroll.scrollTop);
+            self.topRightCollection.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.topLeft = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.topLeftCollection]
+        });
+        this.topRight = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.topRightCollection]
+        });
+        this.bottomLeft = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.bottomLeftCollection]
+        });
+        this.bottomRight = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.bottomRightCollection]
+        });
+        this.contextLayout = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topLeft,
+                top: 0,
+                left: 0
+            }, {
+                el: this.topRight,
+                top: 0
+            }, {
+                el: this.bottomLeft,
+                left: 0
+            }, {
+                el: this.bottomRight
+            }]
+        });
+
+        this.topScrollbar = BI.createWidget({
+            type: "bi.grid_table_scrollbar",
+            width: BI.GridTableScrollbar.SIZE
+        });
+        this.topScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollTop) {
+            self.bottomLeftCollection.setScrollTop(scrollTop);
+            self.bottomRightCollection.setScrollTop(scrollTop);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.leftScrollbar = BI.createWidget({
+            type: "bi.grid_table_horizontal_scrollbar",
+            height: BI.GridTableScrollbar.SIZE
+        });
+        this.leftScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollLeft) {
+            self.topLeftCollection.setScrollLeft(scrollLeft);
+            self.bottomLeftCollection.setScrollLeft(scrollLeft);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.rightScrollbar = BI.createWidget({
+            type: "bi.grid_table_horizontal_scrollbar",
+            height: BI.GridTableScrollbar.SIZE
+        });
+        this.rightScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollLeft) {
+            self.topRightCollection.setScrollLeft(scrollLeft);
+            self.bottomRightCollection.setScrollLeft(scrollLeft);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.scrollBarLayout = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topScrollbar,
+                right: 0,
+                top: 0
+            }, {
+                el: this.leftScrollbar,
+                left: 0
+            }, {
+                el: this.rightScrollbar,
+            }]
+        });
+        this._width = o.width - BI.GridTableScrollbar.SIZE;
+        this._height = o.height - BI.GridTableScrollbar.SIZE;
+        if (o.items.length > 0 || o.header.length < 0) {
+            this._digest();
+            this._populate();
+        }
+    },
+
+    _getFreezeColLength: function () {
+        return this.options.isNeedFreeze ? this.options.freezeCols.length : 0;
+    },
+
+    _populateScrollbar: function () {
+        var o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+        this.topScrollbar.setContentSize(o.items.length * o.rowSize);
+        this.topScrollbar.setSize(this._height - o.header.length * o.headerRowSize);
+        this.topScrollbar.setPosition(this.bottomRightCollection.getScrollTop());
+        this.topScrollbar.populate();
+
+        this.leftScrollbar.setContentSize(totalLeftColumnSize);
+        this.leftScrollbar.setSize(regionSize);
+        this.leftScrollbar.setPosition(this.bottomLeftCollection.getScrollLeft());
+        this.leftScrollbar.populate();
+
+        this.rightScrollbar.setContentSize(totalRightColumnSize);
+        this.rightScrollbar.setSize(this._width - regionSize);
+        this.rightScrollbar.setPosition(this.bottomRightCollection.getScrollLeft());
+        this.rightScrollbar.populate();
+
+        var items = this.scrollBarLayout.attr("items");
+        items[0].top = o.header.length * o.headerRowSize;
+        items[1].top = this._height;
+        items[2].top = this._height;
+        items[2].left = regionSize;
+        this.scrollBarLayout.attr("items", items);
+        this.scrollBarLayout.resize();
+    },
+
+    _populateTable: function () {
+        var self = this, o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+
+        var tlw = regionSize;
+        var tlh = regionSize >= summaryColumnSizeArray[freezeColLength - 1] ? (o.header.length * o.headerRowSize) : (o.header.length * o.headerRowSize + this._scrollBarSize);
+        var trw = this._width - regionSize;
+        var trh = (this._width - regionSize >= totalColumnSize - (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (o.header.length * o.headerRowSize) : (o.header.length * o.headerRowSize + this._scrollBarSize);
+        var blw = (this._height - o.header.length * o.headerRowSize >= totalRowSize) ? regionSize : (regionSize + this._scrollBarSize);
+        var blh = (regionSize >= (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (this._height - o.header.length * o.headerRowSize) : (this._height - o.header.length * o.headerRowSize + this._scrollBarSize);
+        var brw = (this._height - o.header.length * o.headerRowSize >= totalRowSize) ? (this._width - regionSize) : (this._width - regionSize + this._scrollBarSize);
+        var brh = (this._width - regionSize >= totalColumnSize - (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (this._height - o.header.length * o.headerRowSize) : (this._height - o.header.length * o.headerRowSize + this._scrollBarSize);
+
+        var otlw = regionSize;
+        var otlh = o.header.length * o.headerRowSize;
+        var otrw = this._width - regionSize;
+        var otrh = o.header.length * o.headerRowSize;
+        var oblw = regionSize;
+        var oblh = this._height - o.header.length * o.headerRowSize;
+        var obrw = this._width - regionSize;
+        var obrh = this._height - o.header.length * o.headerRowSize;
+
+        var digest = function (w, h, tw, th, el) {
+            if (w >= tw && h >= th) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "hidden",
+                    overflowY: "hidden"
+                })
+            } else if (w >= tw) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "hidden",
+                    overflowY: "auto"
+                })
+            } else if (h >= th) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "auto",
+                    overflowY: "hidden"
+                })
+            } else {
+                el.element.css({
+                    overflow: "auto",
+                    overflowX: "auto",
+                    overflowY: "auto"
+                })
+            }
+        };
+
+        this.topLeft.setWidth(otlw);
+        this.topLeft.setHeight(otlh);
+        this.topRight.setWidth(otrw);
+        this.topRight.setHeight(otrh);
+        this.bottomLeft.setWidth(oblw);
+        this.bottomLeft.setHeight(oblh);
+        this.bottomRight.setWidth(obrw);
+        this.bottomRight.setHeight(obrh);
+
+        this.topLeftCollection.setWidth(tlw);
+        this.topLeftCollection.setHeight(tlh);
+        this.topRightCollection.setWidth(trw);
+        this.topRightCollection.setHeight(trh);
+        this.bottomLeftCollection.setWidth(blw);
+        this.bottomLeftCollection.setHeight(blh);
+        this.bottomRightCollection.setWidth(brw);
+        this.bottomRightCollection.setHeight(brh);
+
+        digest(tlw, tlh, totalLeftColumnSize, o.header.length * o.headerRowSize, this.topLeftCollection);
+        digest(trw, trh, totalRightColumnSize, o.header.length * o.headerRowSize, this.topRightCollection);
+        digest(blw, blh, totalLeftColumnSize, o.items.length * o.rowSize, this.bottomLeftCollection);
+        digest(brw, brh, totalRightColumnSize, o.items.length * o.rowSize, this.bottomRightCollection);
+
+        var items = this.contextLayout.attr("items");
+        items[1].left = regionSize;
+        items[2].top = o.header.length * o.headerRowSize;
+        items[3].left = regionSize;
+        items[3].top = o.header.length * o.headerRowSize;
+        this.contextLayout.attr("items", items);
+        this.contextLayout.resize();
+
+        var leftHeader = [], rightHeader = [], leftItems = [], rightItems = [];
+        var run = function (positions, items, rendered) {
+            BI.each(positions, function (i, item) {
+                var cell = {
+                    type: "bi.collection_table_cell",
+                    cell: items[item.row][item.col]
+                };
+                rendered.push(cell);
+            });
+        };
+        run(this.topLeftItems, o.header, leftHeader);
+        run(this.topRightItems, o.header, rightHeader);
+        run(this.bottomLeftItems, o.items, leftItems);
+        run(this.bottomRightItems, o.items, rightItems);
+
+        this.topLeftCollection.populate(leftHeader);
+        this.topRightCollection.populate(rightHeader);
+        this.bottomLeftCollection.populate(leftItems);
+        this.bottomRightCollection.populate(rightItems);
+    },
+
+    _digest: function () {
+        var o = this.options;
+        var freezeColLength = this._getFreezeColLength();
+        this.topLeftItems = this._serialize(o.header, 0, freezeColLength, o.headerRowSize, o.columnSize, o.mergeCols);
+        this.topRightItems = this._serialize(o.header, freezeColLength, o.columnSize.length, o.headerRowSize, o.columnSize, true);
+        this.bottomLeftItems = this._serialize(o.items, 0, freezeColLength, o.rowSize, o.columnSize, o.mergeCols);
+        this.bottomRightItems = this._serialize(o.items, freezeColLength, o.columnSize.length, o.rowSize, o.columnSize, o.mergeCols);
+    },
+
+    _serialize: function (items, startCol, endCol, rowHeight, columnSize, mergeCols) {
+        var self = this, o = this.options;
+        var result = [], cache = {}, preCol = {}, preRow = {}, map = {};
+        var summaryColumnSize = [];
+        for (var i = startCol; i < endCol; i++) {
+            if (i === startCol) {
+                summaryColumnSize[i] = columnSize[i];
+            } else {
+                summaryColumnSize[i] = summaryColumnSize[i - 1] + columnSize[i];
+            }
+        }
+        var mergeRow = function (i, j) {
+            preCol[j]._height += rowHeight;
+            preCol[j].__mergeRows.push(i);
+        };
+
+        var mergeCol = function (i, j) {
+            preRow[i]._width += columnSize[j];
+            preRow[i].__mergeCols.push(j);
+        };
+
+        var createOneEl = function (r, c) {
+            var width = columnSize[c];
+            var height = rowHeight;
+            map[r][c]._row = r;
+            map[r][c]._col = c;
+            map[r][c]._width = width;
+            map[r][c]._height = height;
+            preCol[c] = map[r][c];
+            preCol[c].__mergeRows = [r];
+            preRow[r] = map[r][c];
+            preRow[r].__mergeCols = [c];
+
+            result.push({
+                x: summaryColumnSize[c] - columnSize[c],
+                y: +r * rowHeight,
+                item: map[r][c]
+            });
+        };
+
+        BI.each(items, function (i, cols) {
+            for (var j = startCol; j < endCol; j++) {
+                if (!cache[i]) {
+                    cache[i] = {};
+                }
+                if (!map[i]) {
+                    map[i] = {};
+                }
+                cache[i][j] = cols[j];
+                map[i][j] = {};
+                if (mergeCols === true || mergeCols.indexOf(j) > -1) {
+                    if (i === 0 && j === startCol) {
+                        createOneEl(0, startCol);
+                    } else if (j === startCol && i > 0) {
+                        var isNeedMergeRow = o.mergeRule(cache[i][j], cache[i - 1][j]);
+                        if (isNeedMergeRow === true) {
+                            mergeRow(i, j);
+                            preRow[i] = preCol[j];
+                        } else {
+                            createOneEl(i, j);
+                        }
+                    } else if (i === 0 && j > startCol) {
+                        var isNeedMergeCol = o.mergeRule(cache[i][j], cache[i][j - 1]);
+                        if (isNeedMergeCol === true) {
+                            mergeCol(i, j);
+                            preCol[j] = preRow[i];
+                        } else {
+                            createOneEl(i, j);
+                        }
+                    } else {
+                        var isNeedMergeRow = o.mergeRule(cache[i][j], cache[i - 1][j]);
+                        var isNeedMergeCol = o.mergeRule(cache[i][j], cache[i][j - 1]);
+                        if (isNeedMergeCol && isNeedMergeRow) {
+                            continue;
+                            //mergeRow(i, j);//优先合并列
+                        }
+                        if (isNeedMergeCol) {
+                            mergeCol(i, j);
+                        }
+                        if (isNeedMergeRow) {
+                            mergeRow(i, j);
+                        }
+                        if (!isNeedMergeCol && !isNeedMergeRow) {
+                            createOneEl(i, j);
+                        }
+                    }
+                } else {
+                    createOneEl(i, j);
+                }
+            }
+        });
+        return BI.map(result, function (i, item) {
+            return {
+                x: item.x,
+                y: item.y,
+                row: item.item._row,
+                col: item.item._col,
+                width: item.item._width,
+                height: item.item._height
+            }
+        });
+    },
+
+    _populate: function () {
+        if (this._width <= 0 || this._height <= 0) {
+            return;
+        }
+        if (this._isNeedDigest === true) {
+            this._digest();
+        }
+        this._populateTable();
+        this._populateScrollbar();
+    },
+
+    getRegionSize: function () {
+        var o = this.options;
+        var regionSize = o.regionColumnSize[0] || 0;
+        if (o.isNeedFreeze === false || o.freezeCols.length === 0) {
+            return 0;
+        }
+        if (!regionSize) {
+            BI.each(o.freezeCols, function (i, col) {
+                regionSize += o.columnSize[col];
+            });
+        }
+        return regionSize;
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.bottomLeftCollection.setScrollTop(scrollTop);
+        this.bottomRightCollection.setScrollTop(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.topLeftCollection.setScrollLeft(scrollLeft);
+        this.bottomLeftCollection.setScrollLeft(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.topRightCollection.setScrollLeft(scrollLeft);
+        this.bottomRightCollection.setScrollLeft(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.bottomRightCollection.getScrollTop();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.bottomLeftCollection.getScrollLeft();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.bottomRightCollection.getScrollLeft();
+    },
+
+    setWidth: function (width) {
+        BI.CollectionTable.superclass.setWidth.apply(this, arguments);
+        this._width = this.options.width - BI.GridTableScrollbar.SIZE;
+    },
+
+    setHeight: function (height) {
+        BI.CollectionTable.superclass.setHeight.apply(this, arguments);
+        this._height = this.options.height - BI.GridTableScrollbar.SIZE;
+    },
+
+    setColumnSize: function (columnSize) {
+        this._isNeedDigest = true;
+        this.options.columnSize = columnSize;
+    },
+
+    setRegionColumnSize: function (regionColumnSize) {
+        this._isNeedDigest = true;
+        this.options.regionColumnSize = regionColumnSize;
+    },
+
+    getColumnSize: function () {
+        return this.options.columnSize;
+    },
+
+    getRegionColumnSize: function () {
+        return this.options.regionColumnSize;
+    },
+
+    populate: function (items, header) {
+        if (items && items !== this.options.items) {
+            this._isNeedDigest = true;
+            this.options.items = items;
+            this._restore();
+        }
+        if (header && header !== this.options.header) {
+            this._isNeedDigest = true;
+            this.options.header = header;
+            this._restore();
+        }
+        this._populate();
+    },
+
+    _restore: function () {
+        this.topLeftCollection.restore();
+        this.topRightCollection.restore();
+        this.bottomLeftCollection.restore();
+        this.bottomRightCollection.restore();
+    },
+
+    restore: function () {
+        this._restore();
+    }
+});
+$.shortcut('bi.collection_table', BI.CollectionTable);/**
+ * QuickCollectionTable
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.QuickCollectionTable
+ * @extends BI.CollectionTable
+ */
+BI.QuickCollectionTable = BI.inherit(BI.CollectionTable, {
+    _defaultConfig: function () {
+        return BI.extend(BI.QuickCollectionTable.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-quick-collection-table"
+        });
+    },
+
+    _init: function () {
+        BI.QuickCollectionTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.topLeftCollection.setOverflowX(false);
+        this.topLeftCollection.setOverflowY(false);
+        this.topRightCollection.setOverflowX(false);
+        this.topRightCollection.setOverflowY(false);
+        this.bottomLeftCollection.setOverflowX(false);
+        this.bottomLeftCollection.setOverflowY(false);
+        this.bottomRightCollection.setOverflowX(false);
+        this.bottomRightCollection.setOverflowY(false);
+        this._leftWheelHandler = new BI.WheelHandler(
+            BI.bind(this._onWheelY, this),
+            BI.bind(this._shouldHandleX, this),
+            BI.bind(this._shouldHandleY, this)
+        );
+        this._rightWheelHandler = new BI.WheelHandler(
+            BI.bind(this._onWheelY, this),
+            BI.bind(this._shouldHandleX, this),
+            BI.bind(this._shouldHandleY, this)
+        );
+        this.bottomLeftCollection.element.mousewheel(function (e) {
+            self._leftWheelHandler.onWheel(e.originalEvent);
+        });
+        this.bottomRightCollection.element.mousewheel(function (e) {
+            self._rightWheelHandler.onWheel(e.originalEvent);
+        });
+    },
+
+    _shouldHandleX: function (delta) {
+        return false;
+    },
+
+    _shouldHandleY: function (delta) {
+        if (delta > 0) {
+            return this.bottomRightCollection.getScrollTop() < this.bottomRightCollection.getMaxScrollTop();
+        } else {
+            return this.bottomRightCollection.getScrollTop() > 0;
+        }
+    },
+
+    _onWheelY: function (deltaX, deltaY) {
+        var self = this;
+        var scrollTop = this.bottomRightCollection.getScrollTop();
+        scrollTop += deltaY;
+        this.bottomLeftCollection.setScrollTop(scrollTop);
+        this.bottomRightCollection.setScrollTop(scrollTop);
+        self._populateScrollbar();
+        this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+    },
+
+    _populateTable: function () {
+        var self = this, o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+
+        var otlw = regionSize;
+        var otlh = o.header.length * o.headerRowSize;
+        var otrw = this._width - regionSize;
+        var otrh = o.header.length * o.headerRowSize;
+        var oblw = regionSize;
+        var oblh = this._height - o.header.length * o.headerRowSize;
+        var obrw = this._width - regionSize;
+        var obrh = this._height - o.header.length * o.headerRowSize;
+
+        this.topLeft.setWidth(otlw);
+        this.topLeft.setHeight(otlh);
+        this.topRight.setWidth(otrw);
+        this.topRight.setHeight(otrh);
+        this.bottomLeft.setWidth(oblw);
+        this.bottomLeft.setHeight(oblh);
+        this.bottomRight.setWidth(obrw);
+        this.bottomRight.setHeight(obrh);
+
+        this.topLeftCollection.setWidth(otlw);
+        this.topLeftCollection.setHeight(otlh);
+        this.topRightCollection.setWidth(otrw);
+        this.topRightCollection.setHeight(otrh);
+        this.bottomLeftCollection.setWidth(oblw);
+        this.bottomLeftCollection.setHeight(oblh);
+        this.bottomRightCollection.setWidth(obrw);
+        this.bottomRightCollection.setHeight(obrh);
+
+        var items = this.contextLayout.attr("items");
+        items[1].left = regionSize;
+        items[2].top = o.header.length * o.headerRowSize;
+        items[3].left = regionSize;
+        items[3].top = o.header.length * o.headerRowSize;
+        this.contextLayout.attr("items", items);
+        this.contextLayout.resize();
+
+        var leftHeader = [], rightHeader = [], leftItems = [], rightItems = [];
+        var run = function (positions, items, rendered) {
+            BI.each(positions, function (i, item) {
+                var cell = {
+                    type: "bi.collection_table_cell",
+                    cell: items[item.row][item.col]
+                };
+                rendered.push(cell);
+            });
+        };
+        run(this.topLeftItems, o.header, leftHeader);
+        run(this.topRightItems, o.header, rightHeader);
+        run(this.bottomLeftItems, o.items, leftItems);
+        run(this.bottomRightItems, o.items, rightItems);
+
+        this.topLeftCollection.populate(leftHeader);
+        this.topRightCollection.populate(rightHeader);
+        this.bottomLeftCollection.populate(leftItems);
+        this.bottomRightCollection.populate(rightItems);
+    }
+});
+$.shortcut('bi.quick_collection_table', BI.QuickCollectionTable);/**
+ *
+ * 表格单元格
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.GridTableCell
+ * @extends BI.Widget
+ */
+BI.GridTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.GridTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-grid-table-cell",
+            width: 0,
+            height: 0,
+            _rowIndex: 0,
+            _columnIndex: 0,
+            _left: 0,
+            _top: 0,
+            cell: {}
+        })
+    },
+
+    _init: function () {
+        BI.GridTableCell.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.cell = BI.createWidget(BI.extend({
+            type: "bi.label"
+        }, o.cell, {
+            cls: (o.cell.cls || "") + "grid-table-cell-wrapper",
+            width: o.width - (o._columnIndex === 0 ? 1 : 0) - 1,
+            height: o.height - (o._rowIndex === 0 ? 1 : 0) - 1
+        }));
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.cell,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    setWidth: function (width) {
+        BI.GridTableCell.superclass.setWidth.apply(this, arguments);
+        var o = this.options;
+        this.cell.setWidth(o.width - (o._columnIndex === 0 ? 1 : 0) - 1);
+    },
+
+    setHeight: function (height) {
+        BI.GridTableCell.superclass.setHeight.apply(this, arguments);
+        var o = this.options;
+        this.cell.setHeight(o.height - (o._rowIndex === 0 ? 1 : 0) - 1);
+    }
+});
+
+$.shortcut("bi.grid_table_cell", BI.GridTableCell);/**
+ * GridTable
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.GridTable
+ * @extends BI.Widget
+ */
+BI.GridTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.GridTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-grid-table",
+            headerRowSize: 25,
+            rowSize: 25,
+            columnSize: [],
+            isNeedFreeze: false,
+            freezeCols: [],
+            header: [],
+            items: [],
+            regionColumnSize: []
+        });
+    },
+
+    _init: function () {
+        BI.GridTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._width = 0;
+        this._height = 0;
+        this._scrollBarSize = BI.DOM.getScrollWidth();
+        var rowHeightGetter = function () {
+            return o.rowSize;
+        };
+        var columnLeftWidthGetter = function (index) {
+            return o.columnSize[index];
+        };
+        var columnRightWidthGetter = function (index) {
+            return o.columnSize[index + self._getFreezeColLength()];
+        };
+        this.topLeftGrid = BI.createWidget({
+            type: "bi.grid_view",
+            rowHeightGetter: rowHeightGetter,
+            columnWidthGetter: columnLeftWidthGetter,
+        });
+        this.topLeftGrid.on(BI.Grid.EVENT_SCROLL, function (scroll) {
+            self.bottomLeftGrid.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.topRightGrid = BI.createWidget({
+            type: "bi.grid_view",
+            rowHeightGetter: rowHeightGetter,
+            columnWidthGetter: columnRightWidthGetter,
+        });
+        this.topRightGrid.on(BI.Grid.EVENT_SCROLL, function (scroll) {
+            self.bottomRightGrid.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.bottomLeftGrid = BI.createWidget({
+            type: "bi.grid_view",
+            rowHeightGetter: rowHeightGetter,
+            columnWidthGetter: columnLeftWidthGetter,
+        });
+        this.bottomLeftGrid.on(BI.Grid.EVENT_SCROLL, function (scroll) {
+            self.bottomRightGrid.setScrollTop(scroll.scrollTop);
+            self.topLeftGrid.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.bottomRightGrid = BI.createWidget({
+            type: "bi.grid_view",
+            rowHeightGetter: rowHeightGetter,
+            columnWidthGetter: columnRightWidthGetter,
+        });
+        this.bottomRightGrid.on(BI.Grid.EVENT_SCROLL, function (scroll) {
+            self.bottomLeftGrid.setScrollTop(scroll.scrollTop);
+            self.topRightGrid.setScrollLeft(scroll.scrollLeft);
+            self._populateScrollbar();
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.topLeft = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.topLeftGrid]
+        });
+        this.topRight = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.topRightGrid]
+        });
+        this.bottomLeft = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.bottomLeftGrid]
+        });
+        this.bottomRight = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.bottomRightGrid]
+        });
+        this.contextLayout = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topLeft,
+                top: 0,
+                left: 0
+            }, {
+                el: this.topRight,
+                top: 0
+            }, {
+                el: this.bottomLeft,
+                left: 0
+            }, {
+                el: this.bottomRight
+            }]
+        });
+
+        this.topScrollbar = BI.createWidget({
+            type: "bi.grid_table_scrollbar",
+            width: BI.GridTableScrollbar.SIZE
+        });
+        this.topScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollTop) {
+            self.bottomLeftGrid.setScrollTop(scrollTop);
+            self.bottomRightGrid.setScrollTop(scrollTop);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.leftScrollbar = BI.createWidget({
+            type: "bi.grid_table_horizontal_scrollbar",
+            height: BI.GridTableScrollbar.SIZE
+        });
+        this.leftScrollbar.on(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, function (scrollLeft) {
+            self.topLeftGrid.setScrollLeft(scrollLeft);
+            self.bottomLeftGrid.setScrollLeft(scrollLeft);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.rightScrollbar = BI.createWidget({
+            type: "bi.grid_table_horizontal_scrollbar",
+            height: BI.GridTableScrollbar.SIZE
+        });
+        this.rightScrollbar.on(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, function (scrollLeft) {
+            self.topRightGrid.setScrollLeft(scrollLeft);
+            self.bottomRightGrid.setScrollLeft(scrollLeft);
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.scrollBarLayout = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topScrollbar,
+                right: 0,
+                top: 0
+            }, {
+                el: this.leftScrollbar,
+                left: 0
+            }, {
+                el: this.rightScrollbar,
+            }]
+        });
+        this._width = o.width - BI.GridTableScrollbar.SIZE;
+        this._height = o.height - BI.GridTableScrollbar.SIZE;
+        this.header = this._getHeader();
+        this.items = this._getItems();
+        if (o.items.length > 0) {
+            this._populate();
+        }
+    },
+
+    _getFreezeColLength: function () {
+        return this.options.isNeedFreeze ? this.options.freezeCols.length : 0;
+    },
+
+    _populateScrollbar: function () {
+        var o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+        this.topScrollbar.setContentSize(o.items.length * o.rowSize);
+        this.topScrollbar.setSize(this._height - o.header.length * o.headerRowSize);
+        this.topScrollbar.setPosition(Math.min(this.bottomLeftGrid.getScrollTop(), this.bottomRightGrid.getScrollTop()));
+        this.topScrollbar.populate();
+
+        this.leftScrollbar.setContentSize(totalLeftColumnSize);
+        this.leftScrollbar.setSize(regionSize);
+        this.leftScrollbar.setPosition(this.bottomLeftGrid.getScrollLeft());
+        this.leftScrollbar.populate();
+
+        this.rightScrollbar.setContentSize(totalRightColumnSize);
+        this.rightScrollbar.setSize(this._width - regionSize);
+        this.rightScrollbar.setPosition(this.bottomRightGrid.getScrollLeft());
+        this.rightScrollbar.populate();
+
+        var items = this.scrollBarLayout.attr("items");
+        items[0].top = o.header.length * o.headerRowSize;
+        items[1].top = this._height;
+        items[2].top = this._height;
+        items[2].left = regionSize;
+        this.scrollBarLayout.attr("items", items);
+        this.scrollBarLayout.resize();
+    },
+
+    _getHeader: function () {
+        var o = this.options;
+        var freezeColLength = this._getFreezeColLength();
+        var leftHeader = [], rightHeader = [];
+        BI.each(o.header, function (i, cols) {
+            leftHeader[i] = [];
+            rightHeader[i] = [];
+            BI.each(cols, function (j, col) {
+                var cell = {
+                    type: "bi.grid_table_cell",
+                    cell: col
+                };
+                if (j < freezeColLength) {
+                    leftHeader[i].push(cell);
+                } else {
+                    rightHeader[i].push(cell);
+                }
+            });
+        });
+        return [leftHeader, rightHeader];
+    },
+
+    _getItems: function () {
+        var o = this.options;
+        var freezeColLength = this._getFreezeColLength();
+        var leftItems = [], rightItems = [];
+        BI.each(o.items, function (i, cols) {
+            leftItems[i] = [];
+            rightItems[i] = [];
+            BI.each(cols, function (j, col) {
+                var cell = {
+                    type: "bi.grid_table_cell",
+                    cell: col
+                };
+                if (j < freezeColLength) {
+                    leftItems[i].push(cell);
+                } else {
+                    rightItems[i].push(cell);
+                }
+            });
+        });
+        return [leftItems, rightItems];
+    },
+
+    _populateTable: function () {
+        var self = this, o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+
+        var tlw = regionSize;
+        var tlh = regionSize >= summaryColumnSizeArray[freezeColLength - 1] ? (o.header.length * o.headerRowSize) : (o.header.length * o.headerRowSize + this._scrollBarSize);
+        var trw = this._width - regionSize;
+        var trh = (this._width - regionSize >= totalColumnSize - (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (o.header.length * o.headerRowSize) : (o.header.length * o.headerRowSize + this._scrollBarSize);
+        var blw = (this._height - o.header.length * o.headerRowSize >= totalRowSize) ? regionSize : (regionSize + this._scrollBarSize);
+        var blh = (regionSize >= (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (this._height - o.header.length * o.headerRowSize) : (this._height - o.header.length * o.headerRowSize + this._scrollBarSize);
+        var brw = (this._height - o.header.length * o.headerRowSize >= totalRowSize) ? (this._width - regionSize) : (this._width - regionSize + this._scrollBarSize);
+        var brh = (this._width - regionSize >= totalColumnSize - (summaryColumnSizeArray[freezeColLength - 1] || 0)) ? (this._height - o.header.length * o.headerRowSize) : (this._height - o.header.length * o.headerRowSize + this._scrollBarSize);
+
+        var otlw = regionSize;
+        var otlh = o.header.length * o.headerRowSize;
+        var otrw = this._width - regionSize;
+        var otrh = o.header.length * o.headerRowSize;
+        var oblw = regionSize;
+        var oblh = this._height - o.header.length * o.headerRowSize;
+        var obrw = this._width - regionSize;
+        var obrh = this._height - o.header.length * o.headerRowSize;
+
+        var digest = function (w, h, tw, th, el) {
+            if (w >= tw && h >= th) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "hidden",
+                    overflowY: "hidden"
+                })
+            } else if (w >= tw) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "hidden",
+                    overflowY: "auto"
+                })
+            } else if (h >= th) {
+                el.element.css({
+                    overflow: "hidden",
+                    overflowX: "auto",
+                    overflowY: "hidden"
+                })
+            } else {
+                el.element.css({
+                    overflow: "auto",
+                    overflowX: "auto",
+                    overflowY: "auto"
+                })
+            }
+        };
+
+        this.topLeft.setWidth(otlw);
+        this.topLeft.setHeight(otlh);
+        this.topRight.setWidth(otrw);
+        this.topRight.setHeight(otrh);
+        this.bottomLeft.setWidth(oblw);
+        this.bottomLeft.setHeight(oblh);
+        this.bottomRight.setWidth(obrw);
+        this.bottomRight.setHeight(obrh);
+
+        this.topLeftGrid.setWidth(tlw);
+        this.topLeftGrid.setHeight(tlh);
+        this.topRightGrid.setWidth(trw);
+        this.topRightGrid.setHeight(trh);
+        this.bottomLeftGrid.setWidth(blw);
+        this.bottomLeftGrid.setHeight(blh);
+        this.bottomRightGrid.setWidth(brw);
+        this.bottomRightGrid.setHeight(brh);
+
+        digest(tlw, tlh, totalLeftColumnSize, o.header.length * o.headerRowSize, this.topLeftGrid);
+        digest(trw, trh, totalRightColumnSize, o.header.length * o.headerRowSize, this.topRightGrid);
+        digest(blw, blh, totalLeftColumnSize, o.items.length * o.rowSize, this.bottomLeftGrid);
+        digest(brw, brh, totalRightColumnSize, o.items.length * o.rowSize, this.bottomRightGrid);
+
+        this.topLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0);
+        this.topLeftGrid.setEstimatedRowSize(o.headerRowSize);
+        this.topRightGrid.setEstimatedColumnSize(totalRightColumnSize / (o.columnSize.length - freezeColLength));
+        this.topRightGrid.setEstimatedRowSize(o.headerRowSize);
+        this.bottomLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0);
+        this.bottomLeftGrid.setEstimatedRowSize(o.rowSize);
+        this.bottomRightGrid.setEstimatedColumnSize(totalRightColumnSize / (o.columnSize.length - freezeColLength));
+        this.bottomRightGrid.setEstimatedRowSize(o.rowSize);
+
+        var items = this.contextLayout.attr("items");
+        items[1].left = regionSize;
+        items[2].top = o.header.length * o.headerRowSize;
+        items[3].left = regionSize;
+        items[3].top = o.header.length * o.headerRowSize;
+        this.contextLayout.attr("items", items);
+        this.contextLayout.resize();
+
+        this.topLeftGrid.populate(this.header[0]);
+        this.topRightGrid.populate(this.header[1]);
+        this.bottomLeftGrid.populate(this.items[0]);
+        this.bottomRightGrid.populate(this.items[1]);
+    },
+
+    _populate: function () {
+        if (this._width <= 0 || this._height <= 0) {
+            return;
+        }
+        this._populateTable();
+        this._populateScrollbar();
+    },
+
+    getRegionSize: function () {
+        var o = this.options;
+        var regionSize = o.regionColumnSize[0] || 0;
+        if (o.isNeedFreeze === false || o.freezeCols.length === 0) {
+            return 0;
+        }
+        if (!regionSize) {
+            BI.each(o.freezeCols, function (i, col) {
+                regionSize += o.columnSize[col];
+            });
+        }
+        return regionSize;
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.bottomLeftGrid.setScrollTop(scrollTop);
+        this.bottomRightGrid.setScrollTop(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.topLeftGrid.setScrollLeft(scrollLeft);
+        this.bottomLeftGrid.setScrollLeft(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.topRightGrid.setScrollLeft(scrollLeft);
+        this.bottomRightGrid.setScrollLeft(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.bottomRightGrid.getScrollTop();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.bottomLeftGrid.getScrollLeft();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.bottomRightGrid.getScrollLeft();
+    },
+
+    setWidth: function (width) {
+        BI.GridTable.superclass.setWidth.apply(this, arguments);
+        this._width = this.options.width - BI.GridTableScrollbar.SIZE;
+    },
+
+    setHeight: function (height) {
+        BI.GridTable.superclass.setHeight.apply(this, arguments);
+        this._height = this.options.height - BI.GridTableScrollbar.SIZE;
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+    },
+
+    setRegionColumnSize: function (regionColumnSize) {
+        this.options.regionColumnSize = regionColumnSize;
+    },
+
+    getColumnSize: function () {
+        return this.options.columnSize;
+    },
+
+    getRegionColumnSize: function () {
+        return this.options.regionColumnSize;
+    },
+
+    populate: function (items, header) {
+        if (items && this.options.items !== items) {
+            this.options.items = items;
+            this.items = this._getItems();
+            this._restore();
+        }
+        if (header && this.options.header !== header) {
+            this.options.header = header;
+            this.header = this._getHeader();
+            this._restore();
+        }
+        this._populate();
+    },
+
+    _restore: function () {
+        this.topLeftGrid.restore();
+        this.topRightGrid.restore();
+        this.bottomLeftGrid.restore();
+        this.bottomRightGrid.restore();
+    },
+
+    restore: function () {
+        this._restore();
+    }
+});
+$.shortcut('bi.grid_table', BI.GridTable);/**
+ * QuickGridTable
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.QuickGridTable
+ * @extends BI.GridTable
+ */
+BI.QuickGridTable = BI.inherit(BI.GridTable, {
+    _defaultConfig: function () {
+        return BI.extend(BI.QuickGridTable.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-quick-grid-table"
+        });
+    },
+
+    _init: function () {
+        BI.QuickGridTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.topLeftGrid.setOverflowX(false);
+        this.topLeftGrid.setOverflowY(false);
+        this.topRightGrid.setOverflowX(false);
+        this.topRightGrid.setOverflowY(false);
+        this.bottomLeftGrid.setOverflowX(false);
+        this.bottomLeftGrid.setOverflowY(false);
+        this.bottomRightGrid.setOverflowX(false);
+        this.bottomRightGrid.setOverflowY(false);
+        this._leftWheelHandler = new BI.WheelHandler(
+            BI.bind(this._onWheelY, this),
+            BI.bind(this._shouldHandleX, this),
+            BI.bind(this._shouldHandleY, this)
+        );
+        this._rightWheelHandler = new BI.WheelHandler(
+            BI.bind(this._onWheelY, this),
+            BI.bind(this._shouldHandleX, this),
+            BI.bind(this._shouldHandleY, this)
+        );
+        this.bottomLeftGrid.element.mousewheel(function (e) {
+            self._leftWheelHandler.onWheel(e.originalEvent);
+        });
+        this.bottomRightGrid.element.mousewheel(function (e) {
+            self._rightWheelHandler.onWheel(e.originalEvent);
+        });
+    },
+
+    _shouldHandleX: function (delta) {
+        return false;
+    },
+
+    _shouldHandleY: function (delta) {
+        if (delta > 0) {
+            return this.bottomRightGrid.getScrollTop() < this.bottomRightGrid.getMaxScrollTop();
+        } else {
+            return this.bottomRightGrid.getScrollTop() > 0;
+        }
+    },
+
+    _onWheelY: function (deltaX, deltaY) {
+        var self = this;
+        var scrollTop = this.bottomRightGrid.getScrollTop();
+        scrollTop += deltaY;
+        this.bottomLeftGrid.setScrollTop(scrollTop);
+        this.bottomRightGrid.setScrollTop(scrollTop);
+        self._populateScrollbar();
+        this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+    },
+
+    _populateTable: function () {
+        var self = this, o = this.options;
+        var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [], totalRowSize = o.items.length * o.rowSize;
+        var freezeColLength = this._getFreezeColLength();
+        BI.each(o.columnSize, function (i, size) {
+            if (o.isNeedFreeze === true && o.freezeCols.contains(i)) {
+                totalLeftColumnSize += size;
+            } else {
+                totalRightColumnSize += size;
+            }
+            totalColumnSize += size;
+            if (i === 0) {
+                summaryColumnSizeArray[i] = size;
+            } else {
+                summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size;
+            }
+        });
+
+        var otlw = regionSize;
+        var otlh = o.header.length * o.headerRowSize;
+        var otrw = this._width - regionSize;
+        var otrh = o.header.length * o.headerRowSize;
+        var oblw = regionSize;
+        var oblh = this._height - o.header.length * o.headerRowSize;
+        var obrw = this._width - regionSize;
+        var obrh = this._height - o.header.length * o.headerRowSize;
+
+        this.topLeft.setWidth(otlw);
+        this.topLeft.setHeight(otlh);
+        this.topRight.setWidth(otrw);
+        this.topRight.setHeight(otrh);
+        this.bottomLeft.setWidth(oblw);
+        this.bottomLeft.setHeight(oblh);
+        this.bottomRight.setWidth(obrw);
+        this.bottomRight.setHeight(obrh);
+
+        this.topLeftGrid.setWidth(otlw);
+        this.topLeftGrid.setHeight(otlh);
+        this.topRightGrid.setWidth(otrw);
+        this.topRightGrid.setHeight(otrh);
+        this.bottomLeftGrid.setWidth(oblw);
+        this.bottomLeftGrid.setHeight(oblh);
+        this.bottomRightGrid.setWidth(obrw);
+        this.bottomRightGrid.setHeight(obrh);
+
+        this.topLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0);
+        this.topLeftGrid.setEstimatedRowSize(o.headerRowSize);
+        this.topRightGrid.setEstimatedColumnSize(totalRightColumnSize / (o.columnSize.length - freezeColLength));
+        this.topRightGrid.setEstimatedRowSize(o.headerRowSize);
+        this.bottomLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0);
+        this.bottomLeftGrid.setEstimatedRowSize(o.rowSize);
+        this.bottomRightGrid.setEstimatedColumnSize(totalRightColumnSize / (o.columnSize.length - freezeColLength));
+        this.bottomRightGrid.setEstimatedRowSize(o.rowSize);
+
+        var items = this.contextLayout.attr("items");
+        items[1].left = regionSize;
+        items[2].top = o.header.length * o.headerRowSize;
+        items[3].left = regionSize;
+        items[3].top = o.header.length * o.headerRowSize;
+        this.contextLayout.attr("items", items);
+        this.contextLayout.resize();
+
+        var leftHeader = [], rightHeader = [], leftItems = [], rightItems = [];
+        BI.each(o.header, function (i, cols) {
+            leftHeader[i] = [];
+            rightHeader[i] = [];
+            BI.each(cols, function (j, col) {
+                var cell = {
+                    type: "bi.grid_table_cell",
+                    cell: col
+                };
+                if (j < freezeColLength) {
+                    leftHeader[i].push(cell);
+                } else {
+                    rightHeader[i].push(cell);
+                }
+            });
+        });
+        BI.each(o.items, function (i, cols) {
+            leftItems[i] = [];
+            rightItems[i] = [];
+            BI.each(cols, function (j, col) {
+                var cell = {
+                    type: "bi.grid_table_cell",
+                    cell: col
+                };
+                if (j < freezeColLength) {
+                    leftItems[i].push(cell);
+                } else {
+                    rightItems[i].push(cell);
+                }
+            });
+        });
+        this.topLeftGrid.populate(leftHeader);
+        this.topRightGrid.populate(rightHeader);
+        this.bottomLeftGrid.populate(leftItems);
+        this.bottomRightGrid.populate(rightItems);
+    }
+});
+$.shortcut('bi.quick_grid_table', BI.QuickGridTable);/**
+ *
+ * 表格滚动条
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.GridTableScrollbar
+ * @extends BI.Widget
+ */
+BI.GridTableScrollbar = BI.inherit(BI.Widget, {
+    _const: {
+        FACE_MARGIN: 4,
+        FACE_MARGIN_2: 4 * 2,
+        FACE_SIZE_MIN: 30,
+        KEYBOARD_SCROLL_AMOUNT: 40
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.GridTableScrollbar.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "scrollbar-layout-main public-scrollbar-main",
+            attributes: {
+                tabIndex: 0
+            },
+            contentSize: 0,
+            defaultPosition: 0,
+            isOpaque: false,
+            orientation: "vertical",
+            position: 0,
+            size: 0
+        })
+    },
+
+    _init: function () {
+        BI.GridTableScrollbar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.focused = false;
+        this.isDragging = false;
+        this.face = BI.createWidget({
+            type: "bi.layout",
+            cls: "scrollbar-layout-face public-scrollbar-face "
+            + (this._isHorizontal() ? "scrollbar-layout-face-horizontal" : "scrollbar-layout-face-vertical")
+        });
+        this.contextLayout = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.face,
+                left: 0,
+                top: 0
+            }]
+        });
+        var onWheel = o.orientation === 'horizontal' ? this._onWheelX : this._onWheelY;
+        this._wheelHandler = new BI.WheelHandler(
+            BI.bind(onWheel, this),
+            BI.bind(this._shouldHandleX, this),
+            BI.bind(this._shouldHandleY, this)
+        );
+        this._mouseMoveTracker = new BI.MouseMoveTracker(
+            BI.bind(this._onMouseMove, this),
+            BI.bind(this._onMouseMoveEnd, this),
+            document
+        );
+        this.element.on("mousedown", BI.bind(this._onMouseDown, this));
+        this.element.on("mousewheel", function (e) {
+            self._wheelHandler.onWheel(e.originalEvent);
+        });
+        this.element.on("keydown", BI.bind(this._onKeyDown, this));
+        this.element.on("focus", function () {
+            self.focused = true;
+            self._populate();
+        });
+        this.element.on("blur", function () {
+            self.focused = false;
+            self._populate();
+        });
+        if (this._isHorizontal()) {
+            this.element.addClass("scrollbar-layout-main-horizontal");
+        } else {
+            this.element.addClass("scrollbar-layout-main-vertical");
+        }
+        this._populate();
+    },
+
+    _isHorizontal: function () {
+        return this.options.orientation === 'horizontal'
+    },
+
+    _getScale: function () {
+        var o = this.options;
+        var scale = o.size / o.contentSize;
+        var faceSize = o.size * scale;
+
+        if (faceSize < this._const.FACE_SIZE_MIN) {
+            scale = (o.size - this._const.FACE_SIZE_MIN) / (o.contentSize - o.size);
+        }
+        return scale;
+    },
+
+    _getFaceSize: function () {
+        var o = this.options;
+        var scale = o.size / o.contentSize;
+        var faceSize = o.size * scale;
+
+        if (faceSize < this._const.FACE_SIZE_MIN) {
+            faceSize = this._const.FACE_SIZE_MIN;
+        }
+        return faceSize;
+    },
+
+    _shouldHandleX: function (delta) {
+        return this.options.orientation === 'horizontal' ?
+            this._shouldHandleChange(delta) :
+            false;
+    },
+
+    _shouldHandleY: function (delta) {
+        return this.options.orientation !== 'horizontal' ?
+            this._shouldHandleChange(delta) :
+            false;
+    },
+
+    _shouldHandleChange: function (delta) {
+        return this.options.position + delta !== this.options.position;
+    },
+
+    _onWheelY: function (deltaX, deltaY) {
+        this._onWheel(deltaY);
+    },
+
+    _onWheelX: function (deltaX, deltaY) {
+        this._onWheel(deltaX);
+    },
+
+    _onWheel: function (delta) {
+        var maxPosition = this.options.contentSize - this.options.size;
+        this.options.position += delta;
+        if (this.options.position < 0) {
+            this.options.position = 0;
+        } else if (this.options.position > maxPosition) {
+            this.options.position = maxPosition;
+        }
+        this._populate();
+        this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position);
+    },
+
+    _onMouseDown: function (e) {
+        if (e.target !== this.face.element[0]) {
+            var position = this._isHorizontal() ? e.offsetX : e.offsetY;
+            position /= this._getScale();
+            this.options.position = BI.clamp(position - (this._getFaceSize() * 0.5 / this._getScale()), 0, this.options.contentSize - this.options.size);
+            this._populate();
+            this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position);
+        } else {
+            this._mouseMoveTracker.captureMouseMoves(e);
+        }
+        this.element[0].focus();
+    },
+
+    _onMouseMove: function (deltaX, deltaY) {
+        var delta = this._isHorizontal() ? deltaX : deltaY;
+        delta /= this._getScale();
+        this.options.position = BI.clamp(this.options.position + delta, 0, this.options.contentSize - this.options.size);
+        this.isDragging = this._mouseMoveTracker.isDragging();
+        this._populate();
+        this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position);
+    },
+
+    _onMouseMoveEnd: function (event) {
+        this._mouseMoveTracker.releaseMouseMoves();
+        if (this.isDragging === true) {
+            this.isDragging = false;
+            this._populate();
+        }
+    },
+
+    _onKeyDown: function (event) {
+        var Keys = {
+            BACKSPACE: 8,
+            TAB: 9,
+            RETURN: 13,
+            ALT: 18,
+            ESC: 27,
+            SPACE: 32,
+            PAGE_UP: 33,
+            PAGE_DOWN: 34,
+            END: 35,
+            HOME: 36,
+            LEFT: 37,
+            UP: 38,
+            RIGHT: 39,
+            DOWN: 40,
+            DELETE: 46,
+            COMMA: 188,
+            PERIOD: 190,
+            A: 65,
+            Z: 90,
+            ZERO: 48,
+            NUMPAD_0: 96,
+            NUMPAD_9: 105
+        };
+        var keyCode = event.keyCode;
+
+        if (keyCode === Keys.TAB) {
+            return;
+        }
+
+        var distance = 40;
+        var direction = 0;
+
+        if (this._isHorizontal()) {
+            switch (keyCode) {
+                case Keys.HOME:
+                    direction = -1;
+                    distance = this.options.contentSize;
+                    break;
+
+                case Keys.LEFT:
+                    direction = -1;
+                    break;
+
+                case Keys.RIGHT:
+                    direction = 1;
+                    break;
+
+                default:
+                    return;
+            }
+        }
+
+        if (!this._isHorizontal()) {
+            switch (keyCode) {
+                case Keys.SPACE:
+                    if (event.shiftKey) {
+                        direction = -1;
+                    } else {
+                        direction = 1;
+                    }
+                    break;
+
+                case Keys.HOME:
+                    direction = -1;
+                    distance = this.options.contentSize;
+                    break;
+
+                case Keys.UP:
+                    direction = -1;
+                    break;
+
+                case Keys.DOWN:
+                    direction = 1;
+                    break;
+
+                case Keys.PAGE_UP:
+                    direction = -1;
+                    distance = this.options.size;
+                    break;
+
+                case Keys.PAGE_DOWN:
+                    direction = 1;
+                    distance = this.options.size;
+                    break;
+
+                default:
+                    return;
+            }
+        }
+
+        this.options.position = BI.clamp(this.options.position + (distance * direction), 0, this.options.contentSize - this.options.size);
+        event.preventDefault();
+        this._populate();
+        this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position);
+    },
+
+    _populate: function () {
+        var self = this, o = this.options;
+        if (o.size < 1 || o.contentSize <= o.size) {
+            this.setVisible(false);
+            return;
+        }
+        this.setVisible(true);
+
+        var size = o.size;
+        var isHorizontal = this._isHorizontal();
+        var isActive = this.focused || this.isDragging;
+
+        var faceSize = this._getFaceSize();
+        var isOpaque = o.isOpaque;
+        this.element[isOpaque === true ? "addClass" : "removeClass"]("public-scrollbar-main-opaque");
+        this.element[isActive === true ? "addClass" : "removeClass"]("public-scrollbar-main-active");
+
+        this.face.element[isActive === true ? "addClass" : "removeClass"]("public-scrollbar-face-active");
+
+        var position = o.position * this._getScale() + this._const.FACE_MARGIN;
+
+        var items = this.contextLayout.attr("items");
+        if (isHorizontal) {
+            this.setWidth(size);
+            this.face.setWidth(faceSize - this._const.FACE_MARGIN_2);
+            items[0].left = position;
+            items[0].top = 0;
+        } else {
+            this.setHeight(size);
+            this.face.setHeight(faceSize - this._const.FACE_MARGIN_2);
+            items[0].left = 0;
+            items[0].top = position;
+        }
+        this.contextLayout.attr("items", items);
+        this.contextLayout.resize();
+    },
+
+    setContentSize: function (contentSize) {
+        this.options.contentSize = contentSize;
+    },
+
+    setPosition: function (position) {
+        this.options.position = position;
+    },
+
+    setSize: function (size) {
+        this.options.size = size;
+    },
+
+    populate: function () {
+        this._populate();
+    }
+});
+BI.GridTableScrollbar.SIZE = 10;
+BI.GridTableScrollbar.EVENT_SCROLL = "EVENT_SCROLL";
+$.shortcut("bi.grid_table_scrollbar", BI.GridTableScrollbar);
+
+
+BI.GridTableHorizontalScrollbar = BI.inherit(BI.Widget, {
+    _const: {
+        FACE_MARGIN: 4,
+        FACE_MARGIN_2: 4 * 2,
+        FACE_SIZE_MIN: 30,
+        KEYBOARD_SCROLL_AMOUNT: 40
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.GridTableHorizontalScrollbar.superclass._defaultConfig.apply(this, arguments), {
+            attributes: {
+                tabIndex: 0
+            },
+            contentSize: 0,
+            position: 0,
+            size: 0
+        })
+    },
+
+    _init: function () {
+        BI.GridTableHorizontalScrollbar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.scrollbar = BI.createWidget({
+            type: "bi.grid_table_scrollbar",
+            orientation: "horizontal",
+            isOpaque: true,
+            position: o.position,
+            contentSize: o.contentSize,
+            size: o.size
+        });
+        this.scrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function () {
+            self.fireEvent(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, arguments);
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            cls: "horizontal-scrollbar",
+            element: this,
+            width: o.size,
+            height: BI.GridTableScrollbar.SIZE,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    scrollable: false,
+                    height: BI.GridTableScrollbar.SIZE,
+                    items: [{
+                        el: this.scrollbar,
+                        left: 0,
+                        top: 0
+                    }]
+                },
+                top: 0,
+                left: 0,
+                right: 0
+            }]
+        });
+    },
+
+    setContentSize: function (contentSize) {
+        this.options.contentSize = contentSize;
+        this.scrollbar.setContentSize(contentSize);
+    },
+
+    setPosition: function (position) {
+        this.options.position = position;
+        this.scrollbar.setPosition(position);
+    },
+
+    setSize: function (size) {
+        this.setWidth(size);
+        this.options.size = size;
+        this.scrollbar.setSize(size);
+    },
+
+    populate: function () {
+        this.scrollbar.populate();
+    }
+});
+BI.GridTableHorizontalScrollbar.EVENT_SCROLL = "EVENT_SCROLL";
+$.shortcut("bi.grid_table_horizontal_scrollbar", BI.GridTableHorizontalScrollbar);/**
+ *
+ * 表格
+ *
+ * Created by GUY on 2015/9/22.
+ * @class BI.TableHeaderCell
+ * @extends BI.Single
+ */
+BI.TableHeaderCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TableHeaderCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-table-header-cell",
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TableHeaderCell.superclass._init.apply(this, arguments);
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "center",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+
+$.shortcut("bi.table_header_cell", BI.TableHeaderCell);/**
+ *
+ * 表格
+ *
+ * 能处理静态宽度以及动态宽度的表, 百分比宽度的表请使用PreviewTable
+ *
+ * Created by GUY on 2015/9/22.
+ * @class BI.Table
+ * @extends BI.Widget
+ */
+BI.Table = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Table.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-table",
+            logic: { //冻结的页面布局逻辑
+                dynamic: false
+            },
+
+            isNeedResize: false,//是否需要调整列宽
+            isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 25,
+            footerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: false,
+
+            header: [],
+            footer: false,
+            items: [] //二维数组
+        })
+    },
+
+    _calculateWidth: function (width) {
+        if (!width || width === "0") {
+            return "";
+        }
+        width = BI.parseFloat(width);
+        if (width < 0) {
+            width = 0;
+        }
+        return width > 1.01 ? width : (width * 100 + "%");
+    },
+
+    _calculateHeight: function (height) {
+        return height ? height : "";
+    },
+
+    _isRightFreeze: function () {
+        return BI.isNotEmptyArray(this.options.freezeCols) && BI.first(this.options.freezeCols) !== 0;
+    },
+
+    _createTopLeft: function () {
+        var o = this.options, isRight = this._isRightFreeze();
+        this.topLeftColGroupTds = {};
+        this.topLeftBodyTds = {};
+        this.topLeftBodyItems = {};
+        var table = this._table();
+        var colgroup = this._createColGroup(this.columnLeft, this.topLeftColGroupTds);
+        var body = this.topLeftBody = this._body();
+        body.element.append(this._createHeaderCells(this.topLeftItems, this.columnLeft, this.mergeLeft, this.topLeftBodyTds, this.topLeftBodyItems));
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: table,
+            items: [colgroup, body]
+        });
+        if (isRight) {
+            var w = 0;
+            BI.each(o.columnSize, function (i, col) {
+                if (!o.freezeCols.contains(i)) {
+                    w += col;
+                }
+            });
+            if (BI.isNumeric(w) && w > 1) {
+                w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length;
+            }
+        }
+        return (this.topLeftContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: this._calculateWidth(w),
+            items: [table]
+        }));
+    },
+
+    _createTopRight: function () {
+        var o = this.options, isRight = this._isRightFreeze();
+        this.topRightColGroupTds = {};
+        this.topRightBodyTds = {};
+        this.topRightBodyItems = {};
+        var table = this._table();
+        var colgroup = this._createColGroup(this.columnRight, this.topRightColGroupTds);
+        var body = this.topRightBody = this._body();
+        body.element.append(this._createHeaderCells(this.topRightItems, this.columnRight, this.mergeRight, this.topRightBodyTds, this.topRightBodyItems, this.columnLeft.length));
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: table,
+            items: [colgroup, body]
+        });
+        if (!isRight) {
+            var w = 0;
+            BI.each(o.columnSize, function (i, col) {
+                if (!o.freezeCols.contains(i)) {
+                    w += col;
+                }
+            });
+            if (BI.isNumeric(w)) {
+                w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length;
+            }
+        }
+        return (this.topRightContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: w || undefined,
+            items: [table]
+        }));
+    },
+
+    _createBottomLeft: function () {
+        var o = this.options, isRight = this._isRightFreeze();
+        this.bottomLeftColGroupTds = {};
+        this.bottomLeftBodyTds = {};
+        this.bottomLeftBodyItems = {};
+        var table = this._table();
+        var colgroup = this._createColGroup(this.columnLeft, this.bottomLeftColGroupTds);
+        var body = this._createBottomLeftBody();
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: table,
+            items: [colgroup, body]
+        });
+        if (isRight) {
+            var w = 0;
+            BI.each(o.columnSize, function (i, col) {
+                if (!o.freezeCols.contains(i)) {
+                    w += col;
+                }
+            });
+            if (BI.isNumeric(w) && w > 1) {
+                w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length;
+            }
+        }
+        return (this.bottomLeftContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: this._calculateWidth(w),
+            items: [table]
+        }));
+    },
+
+    _createBottomLeftBody: function () {
+        var body = this.bottomLeftBody = this._body();
+        body.element.append(this._createCells(this.bottomLeftItems, this.columnLeft, this.mergeLeft, this.bottomLeftBodyTds, this.bottomLeftBodyItems));
+        return body;
+    },
+
+    _createBottomRight: function () {
+        var o = this.options, isRight = this._isRightFreeze();
+        this.bottomRightColGroupTds = {};
+        this.bottomRightBodyTds = {};
+        this.bottomRightBodyItems = {};
+        var table = this._table();
+        var colgroup = this._createColGroup(this.columnRight, this.bottomRightColGroupTds);
+        var body = this._createBottomRightBody();
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: table,
+            items: [colgroup, body]
+        });
+        if (!isRight) {
+            var w = 0;
+            BI.each(o.columnSize, function (i, col) {
+                if (!o.freezeCols.contains(i)) {
+                    w += col;
+                }
+            });
+            if (BI.isNumeric(w) && w > 1) {
+                w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length;
+            }
+        }
+        return (this.bottomRightContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: this._calculateWidth(w),
+            items: [table]
+        }));
+    },
+
+    _createBottomRightBody: function () {
+        var body = this.bottomRightBody = this._body();
+        body.element.append(this._createCells(this.bottomRightItems, this.columnRight, this.mergeRight, this.bottomRightBodyTds, this.bottomRightBodyItems, this.columnLeft.length));
+        return body;
+    },
+
+    _createFreezeTable: function () {
+        var self = this, o = this.options;
+        var isRight = this._isRightFreeze();
+        var split = this._split(o.header);
+        this.topLeftItems = split.left;
+        this.topRightItems = split.right;
+        split = this._split(o.items);
+        this.bottomLeftItems = split.left;
+        this.bottomRightItems = split.right;
+
+        this.columnLeft = [];
+        this.columnRight = [];
+        BI.each(o.columnSize, function (i, size) {
+            if (o.freezeCols.contains(i)) {
+                self[isRight ? "columnRight" : "columnLeft"].push(size);
+            } else {
+                self[isRight ? "columnLeft" : "columnRight"].push(size);
+            }
+        });
+        this.mergeLeft = [];
+        this.mergeRight = [];
+        BI.each(o.mergeCols, function (i, col) {
+            if (o.freezeCols.contains(col)) {
+                self[isRight ? "mergeRight" : "mergeLeft"].push(col);
+            } else {
+                self[isRight ? "mergeLeft" : "mergeRight"].push(col);
+            }
+        });
+
+        var topLeft = this._createTopLeft();
+        var topRight = this._createTopRight();
+        var bottomLeft = this._createBottomLeft();
+        var bottomRight = this._createBottomRight();
+
+        this.scrollTopLeft = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "scroll-top-left",
+            width: "100%",
+            height: "100%",
+            scrollable: false,
+            items: [topLeft]
+        });
+        this.scrollTopRight = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "scroll-top-right",
+            width: "100%",
+            height: "100%",
+            scrollable: false,
+            items: [topRight]
+        });
+        this.scrollBottomLeft = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "scroll-bottom-left",
+            width: "100%",
+            height: "100%",
+            scrollable: isRight || null,
+            scrollx: !isRight,
+            items: [bottomLeft]
+        });
+        this.scrollBottomRight = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "scroll-bottom-right",
+            width: "100%",
+            height: "100%",
+            scrollable: !isRight || null,
+            scrollx: isRight,
+            items: [bottomRight]
+        });
+        this.topLeft = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "top-left",
+            scrollable: false,
+            items: [this.scrollTopLeft]
+        });
+        this.topRight = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "top-right",
+            scrollable: false,
+            items: [this.scrollTopRight]
+        });
+        this.bottomLeft = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "bottom-left",
+            // scrollable: false,
+            items: [this.scrollBottomLeft]
+        });
+        this.bottomRight = BI.createWidget({
+            type: "bi.adaptive",
+            cls: "bottom-right",
+            scrollable: false,
+            items: [this.scrollBottomRight]
+        });
+
+        var headerHeight = o.header.length * ((o.headerRowSize || o.rowSize) + 1) + 1;
+        var leftWidth = BI.sum(o.freezeCols, function (i, col) {
+            return o.columnSize[col] > 1 ? o.columnSize[col] + 1 : o.columnSize[col];
+        });
+
+        if (o.isNeedResize) {
+            var resizer;
+            var createResizer = function (size, position) {
+                var rowSize = self.getCalculateRegionRowSize();
+                resizer = BI.createWidget({
+                    type: "bi.layout",
+                    cls: "bi-resizer",
+                    width: size.width,
+                    height: rowSize[0] + rowSize[1]
+                });
+                BI.createWidget({
+                    type: "bi.absolute",
+                    element: "body",
+                    items: [{
+                        el: resizer,
+                        left: position.left,
+                        top: position.top - rowSize[0]
+                    }]
+                });
+            };
+            var resizeResizer = function (size, position) {
+                var rowSize = self.getCalculateRegionRowSize();
+                var columnSize = self.getCalculateRegionColumnSize();
+                var height = rowSize[0] + rowSize[1];
+                var sumSize = columnSize[0] + columnSize[1];
+                if (size.width > sumSize / 5 * 4) {
+                    size.width = sumSize / 5 * 4;
+                }
+                if (size.width < 10) {
+                    size.width = 10;
+                }
+                resizer.element.css({
+                    "left": position.left + "px",
+                    "width": size.width + "px",
+                    "height": height + "px"
+                });
+            };
+            var stopResizer = function () {
+                resizer && resizer.destroy();
+                resizer = null;
+            };
+            var handle;
+            if (o.freezeCols.length > 0 && o.freezeCols.length < o.columnSize.length) {
+                if (isRight) {
+                    var options = {
+                        handles: "w",
+                        minWidth: 15,
+                        helper: "clone",
+                        start: function (event, ui) {
+                            createResizer(ui.size, ui.position);
+                            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE);
+                        },
+                        resize: function (e, ui) {
+                            resizeResizer(ui.size, ui.position);
+                            self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE);
+                            e.stopPropagation();
+                            //return false;
+                        },
+                        stop: function (e, ui) {
+                            stopResizer();
+                            if (o.isResizeAdapt) {
+                                var increment = ui.size.width - (BI.sum(self.columnRight) + self.columnRight.length);
+                                o.columnSize[self.columnLeft.length] += increment;
+                            } else {
+                                self.setRegionColumnSize(["fill", ui.size.width]);
+                            }
+                            self._resize();
+                            ui.element.css("left", "");
+                            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE);
+                        }
+                    };
+                    self.bottomRight.element.resizable(options);
+                    handle = $(".ui-resizable-handle", this.bottomRight.element).css("top", -1 * headerHeight);
+                } else {
+                    var options = {
+                        handles: "e",
+                        minWidth: 15,
+                        helper: "clone",
+                        start: function (event, ui) {
+                            createResizer(ui.size, ui.position);
+                            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE);
+                        },
+                        resize: function (e, ui) {
+                            resizeResizer(ui.size, ui.position);
+                            self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE);
+                            e.stopPropagation();
+                            //return false;
+                        },
+                        stop: function (e, ui) {
+                            stopResizer();
+                            if (o.isResizeAdapt) {
+                                var increment = ui.size.width - (BI.sum(self.columnLeft) + self.columnLeft.length);
+                                o.columnSize[self.columnLeft.length - 1] += increment;
+                            } else {
+                                self.setRegionColumnSize([ui.size.width, "fill"]);
+                            }
+                            self._resize();
+                            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE);
+                        }
+                    };
+                    self.bottomLeft.element.resizable(options);
+                    handle = $(".ui-resizable-handle", this.bottomLeft.element).css("top", -1 * headerHeight);
+                }
+            }
+        }
+        this._resize = function () {
+            if (self.scrollBottomLeft.element.is(":visible")) {
+                self.scrollBottomLeft.element.css({"overflow-x": "auto"});
+                self.scrollBottomRight.element.css({"overflow-x": "auto"});
+                self.setColumnSize(o.columnSize);
+                if (isRight) {
+                    self.scrollBottomLeft.element.css({"overflow-y": "auto"});
+                } else {
+                    self.scrollBottomRight.element.css({"overflow-y": "auto"});
+                }
+                if (self.scrollBottomLeft.element.hasHorizonScroll() || self.scrollBottomRight.element.hasHorizonScroll()) {
+                    self.scrollBottomLeft.element.css("overflow-x", "scroll");
+                    self.scrollBottomRight.element.css("overflow-x", "scroll");
+                }
+                if (self.scrollBottomRight.element.hasVerticalScroll()) {
+                    self.scrollTopRight.element.css("overflow-y", "scroll");
+                } else {
+                    self.scrollTopRight.element.css("overflow-y", "hidden");
+                }
+                if (self.scrollBottomLeft.element.hasVerticalScroll()) {
+                    self.scrollTopLeft.element.css("overflow-y", "scroll");
+                } else {
+                    self.scrollTopLeft.element.css("overflow-y", "hidden");
+                }
+                self.scrollTopLeft.element[0].scrollLeft = self.scrollBottomLeft.element[0].scrollLeft;
+                self.scrollTopRight.element[0].scrollLeft = self.scrollBottomRight.element[0].scrollLeft;
+                self.scrollBottomLeft.element[0].scrollTop = self.scrollBottomRight.element[0].scrollTop;
+                //调整拖拽handle的高度
+                if (o.isNeedResize) {
+                    handle && handle.css("height", self.bottomLeft.element.height() + headerHeight);
+                }
+            }
+        };
+
+        var regionColumnSize = o.regionColumnSize;
+        if (o.freezeCols.length === 0) {
+            regionColumnSize = isRight ? ['fill', 0] : [0, 'fill'];
+        } else if (o.freezeCols.length >= o.columnSize.length) {
+            regionColumnSize = isRight ? [0, 'fill'] : ['fill', 0];
+        }
+        this.partitions = BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, {
+            rows: 2,
+            columns: 2,
+            columnSize: regionColumnSize || (isRight ? ['fill', leftWidth] : [leftWidth, 'fill']),
+            rowSize: [headerHeight, 'fill'],
+            items: [[{
+                el: this.topLeft
+            }, {
+                el: this.topRight
+            }], [{
+                el: this.bottomLeft
+            }, {
+                el: this.bottomRight
+            }]]
+        }))));
+
+        //var scrollElement = isRight ? scrollBottomLeft.element : scrollBottomRight.element;
+        //var scrollTopElement = isRight ? scrollTopLeft.element : scrollTopRight.element;
+        //var otherElement = isRight ? scrollBottomRight.element : scrollBottomLeft.element;
+
+        this._initFreezeScroll();
+        BI.nextTick(function () {
+            if (self.element.is(":visible")) {
+                self._resize();
+                self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT);
+            }
+        });
+        BI.Resizers.add(this.getName(), function (e) {
+            if (BI.isWindow(e.target) && self.element.is(":visible")) {
+                self._resize();
+                self.fireEvent(BI.Table.EVENT_TABLE_RESIZE);
+            }
+        });
+    },
+
+    _initFreezeScroll: function () {
+        var self = this, o = this.options;
+        scroll(this.scrollBottomRight.element, this.scrollTopRight.element, this.scrollBottomLeft.element);
+        scroll(this.scrollBottomLeft.element, this.scrollTopLeft.element, this.scrollBottomRight.element);
+
+        function scroll(scrollElement, scrollTopElement, otherElement) {
+            var scrolling, scrollingX;
+            var fn = function (event, delta, deltaX, deltaY) {
+                var inf = self._getScrollOffsetAndDur(event);
+                if (deltaY < 0 || deltaY > 0) {
+                    if (scrolling) {
+                        scrollElement[0].scrollTop = scrolling;
+                    }
+                    scrolling = scrollElement[0].scrollTop - delta * inf.offset;
+                    var stopPropagation = false;
+                    var st = scrollElement[0].scrollTop;
+                    scrollElement[0].scrollTop = scrolling;
+                    if (scrollElement[0].scrollTop !== st) {
+                        stopPropagation = true;
+                    }
+                    scrollElement[0].scrollTop = st;
+                    self._animateScrollTo(scrollElement, scrollElement[0].scrollTop, scrolling, inf.dur, "linear", {
+                        onStart: function () {
+                        },
+                        onUpdate: function (top) {
+                            otherElement[0].scrollTop = top;
+                            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, top);
+                        },
+                        onComplete: function () {
+                            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, scrolling);
+                            scrolling = null;
+                        }
+                    });
+
+
+                    //otherElement[0].scrollTop = scrollTop;
+                    //scrollElement[0].scrollTop = scrollTop;
+                    //self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, scrollTop);
+                    if (stopPropagation === true) {
+                        event.stopPropagation();
+                        return false;
+                    }
+                    return;
+                }
+                //if (deltaX < 0 || deltaX > 0) {
+                //    if (scrollingX) {
+                //        scrollElement[0].scrollLeft = scrollingX;
+                //    }
+                //    scrollingX = scrollElement[0].scrollLeft + delta * inf.offset;
+                //    var stopPropagation = false;
+                //    var sl = scrollElement[0].scrollLeft;
+                //    scrollElement[0].scrollLeft = scrollingX;
+                //    if (scrollElement[0].scrollLeft !== sl) {
+                //        stopPropagation = true;
+                //    }
+                //    scrollElement[0].scrollLeft = sl;
+                //    self._animateScrollTo(scrollElement, scrollElement[0].scrollLeft, scrollingX, inf.dur, "linear", {
+                //        direction: "left",
+                //        onStart: function () {
+                //        },
+                //        onUpdate: function (left) {
+                //            scrollTopElement[0].scrollLeft = left;
+                //            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, null, left);
+                //        },
+                //        onComplete: function () {
+                //            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, null, scrollingX);
+                //            scrollingX = null;
+                //        }
+                //    });
+                //
+                //
+                //    //otherElement[0].scrollTop = scrollTop;
+                //    //scrollElement[0].scrollTop = scrollTop;
+                //    //self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, scrollTop);
+                //    if (stopPropagation === true) {
+                //        event.stopPropagation();
+                //        return false;
+                //    }
+                //}
+            };
+            scrollElement.mousewheel(fn);
+            var scrollTop = 0, scrollLeft = 0;
+            scrollElement.scroll(function (e) {
+                var change = false;
+                if (scrollElement.scrollTop() != scrollTop) {
+                    var old = otherElement.scrollTop();
+                    otherElement.scrollTop(scrollElement.scrollTop());
+                    scrollTop = scrollElement.scrollTop();
+                    if (Math.abs(old - otherElement[0].scrollTop) > 0.1) {
+                        e.stopPropagation();
+                        change = true;
+                    }
+                }
+                if (scrollElement.scrollLeft() != scrollLeft) {
+                    var old = scrollTopElement.scrollLeft();
+                    scrollTopElement.scrollLeft(scrollElement.scrollLeft());
+                    scrollLeft = scrollElement.scrollLeft();
+                    if (Math.abs(old - scrollTopElement[0].scrollLeft) > 0.1) {
+                        e.stopPropagation();
+                        change = true;
+                    }
+                }
+                // self.fireEvent(BI.Table.EVENT_TABLE_SCROLL);
+                if (change === true) {
+                    e.stopPropagation();
+                    //return false;
+                }
+            });
+        }
+    },
+
+    _animateScrollTo: function (el, from, to, duration, easing, op) {
+        var self = this;
+        var onStart = op.onStart, onComplete = op.onComplete, onUpdate = op.onUpdate;
+        var startTime = BI.getTime(), _delay, progress = 0, _request;
+        _cancelTween();
+        _startTween();
+        var diff = to - from;
+        el._stop = 0;
+        function _step() {
+            if (el._stop) {
+                return;
+            }
+            if (!progress) {
+                onStart.call();
+            }
+            progress = BI.getTime() - startTime;
+            _tween();
+            if (progress >= el.time) {
+                el.time = (progress > el.time) ? progress + _delay - (progress - el.time) : progress + _delay - 1;
+                if (el.time < progress + 1) {
+                    el.time = progress + 1;
+                }
+            }
+            if (el.time < duration) {
+                el._id = _request(_step);
+            } else {
+                el[op.direction == 'left' ? "scrollLeft" : "scrollTop"](to);
+                onComplete.call();
+            }
+        }
+
+        function _tween() {
+            var top = to;
+            if (duration > 0) {
+                el.currVal = _ease(el.time, from, diff, duration, easing);
+                el[op.direction == 'left' ? "scrollLeft" : "scrollTop"](top = Math.round(el.currVal));
+            } else {
+                el[op.direction == 'left' ? "scrollLeft" : "scrollTop"](to);
+            }
+            onUpdate(top);
+        }
+
+        function _startTween() {
+            _delay = 1000 / 60;
+            el.time = progress + _delay;
+            _request = (!requestAnimationFrame()) ? function (f) {
+                _tween();
+                return setTimeout(f, 0.01);
+            } : requestAnimationFrame();
+            el._id = _request(_step);
+        }
+
+        function requestAnimationFrame() {
+            return window.requestAnimationFrame ||
+                window.webkitRequestAnimationFrame ||
+                window.mozRequestAnimationFrame ||
+                window.msRequestAnimationFrame ||
+                window.oRequestAnimationFrame;
+        }
+
+        function cancelAnimationFrame() {
+            return window.cancelAnimationFrame ||
+                window.webkitCancelAnimationFrame ||
+                window.mozCancelAnimationFrame ||
+                window.msCancelAnimationFrame ||
+                window.oCancelAnimationFrame ||
+                window.cancelRequestAnimationFrame ||
+                window.webkitCancelRequestAnimationFrame ||
+                window.mozCancelRequestAnimationFrame ||
+                window.msCancelRequestAnimationFrame ||
+                window.oCancelRequestAnimationFrame
+        }
+
+        function _cancelTween() {
+            if (el._id == null) {
+                return;
+            }
+            if (!cancelAnimationFrame()) {
+                clearTimeout(el._id);
+            } else {
+                cancelAnimationFrame()(el._id);
+            }
+            el._id = null;
+        }
+
+        function _ease(t, b, c, d, type) {
+            switch (type) {
+                case "linear":
+                    return c * t / d + b;
+                    break;
+                case "mcsLinearOut":
+                    t /= d;
+                    t--;
+                    return c * Math.sqrt(1 - t * t) + b;
+                    break;
+                case "easeInOutSmooth":
+                    t /= d / 2;
+                    if (t < 1) {
+                        return c / 2 * t * t + b;
+                    }
+                    t--;
+                    return -c / 2 * (t * (t - 2) - 1) + b;
+                    break;
+                case "easeInOutStrong":
+                    t /= d / 2;
+                    if (t < 1) {
+                        return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
+                    }
+                    t--;
+                    return c / 2 * ( -Math.pow(2, -10 * t) + 2 ) + b;
+                    break;
+                case "easeInOut":
+                case "mcsEaseInOut":
+                    t /= d / 2;
+                    if (t < 1) {
+                        return c / 2 * t * t * t + b;
+                    }
+                    t -= 2;
+                    return c / 2 * (t * t * t + 2) + b;
+                    break;
+                case "easeOutSmooth":
+                    t /= d;
+                    t--;
+                    return -c * (t * t * t * t - 1) + b;
+                    break;
+                case "easeOutStrong":
+                    return c * ( -Math.pow(2, -10 * t / d) + 1 ) + b;
+                    break;
+                case "easeOut":
+                case "mcsEaseOut":
+                default:
+                    var ts = (t /= d) * t, tc = ts * t;
+                    return b + c * (0.499999999999997 * tc * ts + -2.5 * ts * ts + 5.5 * tc + -6.5 * ts + 4 * t);
+            }
+        }
+    },
+
+    _getScrollOffsetAndDur: function (event) {
+        var offset = 40, dur = 200;
+        if (event.originalEvent.wheelDelta) {
+            offset = Math.abs(event.originalEvent.wheelDelta);
+        }
+        if (event.deltaFactor < 2) {
+            offset = 3;
+            dur = 17;
+        }
+        return {
+            offset: offset,
+            dur: dur
+        };
+    },
+
+    resize: function () {
+        this._resize();
+    },
+
+    _createCells: function (items, columnSize, mergeCols, TDs, Ws, start, rowSize) {
+        var self = this, o = this.options, preCol = {}, preRow = {}, preRW = {}, preCW = {}, map = {};
+        columnSize = columnSize || o.columnSize;
+        mergeCols = mergeCols || o.mergeCols;
+        TDs = TDs || {};
+        Ws = Ws || {};
+        start = start || 0;
+        rowSize || (rowSize = o.rowSize);
+        var frag = document.createDocumentFragment();
+        BI.each(items, function (i, rows) {
+            var tr = $("<tr>").addClass((i & 1) === 0 ? "odd" : "even");
+            BI.each(rows, function (j, row) {
+                if (!map[i]) {
+                    map[i] = {};
+                }
+                if (!TDs[i]) {
+                    TDs[i] = {};
+                }
+                if (!Ws[i]) {
+                    Ws[i] = {};
+                }
+                map[i][j] = row;
+
+                if (o.isNeedMerge && mergeCols.contains(j)) {
+                    if (i === 0 && j === 0) {
+                        createOneEl(0, 0);
+                    } else if (j === 0 && i > 0) {
+                        var isNeedMergeRow = o.mergeRule(map[i][j], map[i - 1][j]);
+                        if (isNeedMergeRow === true) {
+                            mergeRow(i, j);
+                            preRow[i] = preCol[j];
+                            preRW[i] = preCW[j];
+                        } else {
+                            createOneEl(i, j);
+                        }
+                    } else if (i === 0 && j > 0) {
+                        var isNeedMergeCol = o.mergeRule(map[i][j], map[i][j - 1]);
+                        if (isNeedMergeCol === true) {
+                            mergeCol(i, j);
+                            preCol[j] = preRow[j - 1];
+                            preCW[j] = preRW[j - 1];
+                        } else {
+                            createOneEl(i, j);
+                        }
+                    } else {
+                        var isNeedMergeRow = o.mergeRule(map[i][j], map[i - 1][j]);
+                        var isNeedMergeCol = o.mergeRule(map[i][j], map[i][j - 1]);
+                        if (isNeedMergeCol && isNeedMergeRow) {
+                            return;
+                        }
+                        if (isNeedMergeCol) {
+                            mergeCol(i, j);
+                        }
+                        if (isNeedMergeRow) {
+                            mergeRow(i, j);
+                        }
+                        if (!isNeedMergeCol && !isNeedMergeRow) {
+                            createOneEl(i, j);
+                        }
+                    }
+                } else {
+                    createOneEl(i, j);
+                }
+            });
+            function mergeRow(i, j) {
+                var height = (preCol[j].attr("height") | 0) + rowSize + 1;
+                preCol[j].attr("height", height).css("height", height);
+                //preCW[j].element.css("height", height);
+                var rowspan = ((preCol[j].attr("rowspan") || 1) | 0) + 1;
+                preCol[j].attr("rowspan", rowspan);
+                preCol[j].__mergeRows.pushDistinct(i);
+                TDs[i][j] = preCol[j];
+                Ws[i][j] = preCW[j];
+            }
+
+            function mergeCol(i, j) {
+                if (columnSize[j]) {
+                    var width = preRow[i].attr("width") | 0;
+                    if (width > 1.05 && columnSize[j]) {
+                        width = width + columnSize[j] + 1;
+                        if (j === columnSize.length - 1) {
+                            width--;
+                        }
+                    } else {
+                        width = width + columnSize[j]
+                    }
+                    width = self._calculateWidth(width);
+                    preRow[i].attr("width", width).css("width", width);
+                    preRW[i].element.width(width);
+                }
+                var colspan = ((preRow[i].attr("colspan") || 1) | 0) + 1;
+                preRow[i].attr("colspan", colspan);
+                preRow[i].__mergeCols.pushDistinct(j);
+                TDs[i][j] = preRow[i];
+                Ws[i][j] = preRW[i];
+            }
+
+            function createOneEl(r, c) {
+                var width = self._calculateWidth(columnSize[c]);
+                if (width > 1.05 && c === columnSize.length - 1) {
+                    width--;
+                }
+                var height = self._calculateHeight(rowSize);
+                var td = $("<td>").attr("height", height)
+                    .attr("width", width).css({"width": width, "height": height, "position": "relative"})
+                    .addClass((c & 1) === 0 ? "odd-col" : "even-col")
+                    .addClass(r === 0 ? "first-row" : "")
+                    .addClass(c === 0 ? "first-col" : "")
+                    .addClass(c === rows.length - 1 ? "last-col" : "");
+                var w = BI.createWidget(map[r][c], {
+                    type: "bi.table_cell",
+                    textAlign: "left",
+                    width: BI.isNumeric(width) ? width : "",
+                    height: BI.isNumeric(height) ? height : "",
+                    _row: r,
+                    _col: c + start
+                });
+                w.element.css("position", "relative");
+                td.append(w.element);
+                tr.append(td);
+                preCol[c] = td;
+                preCol[c].__mergeRows = [r];
+                preCW[c] = w;
+                preRow[r] = td;
+                preRow[r].__mergeCols = [c];
+                preRW[r] = w;
+                TDs[r][c] = td;
+                Ws[r][c] = w;
+            }
+
+            frag.appendChild(tr[0]);
+        });
+        return frag;
+    },
+
+    _createColGroupCells: function (columnSize, store) {
+        var self = this, o = this.options;
+        columnSize = columnSize || o.columnSize;
+        store = store || {};
+        var frag = document.createDocumentFragment();
+        BI.each(columnSize, function (i, size) {
+            var width = self._calculateWidth(size);
+            var col = $("<col>").attr("width", width).css("width", width);
+            store[i] = col;
+            frag.appendChild(col[0]);
+        });
+        return frag;
+    },
+
+    _createHeaderCells: function (items, columnSize, mergeCols, TDs, Ws, start) {
+        var self = this, o = this.options;
+        start || (start = 0);
+        var frag = this._createCells(items, columnSize, BI.range(o.columnSize.length), TDs, Ws, start, o.headerRowSize || o.rowSize);
+
+        if (o.isNeedResize === true) {
+            var tds = TDs[BI.size(TDs) - 1];
+            BI.each(tds, function (j, td) {
+                j = j | 0;
+                var resizer;
+                var getHeight = function (size, position) {
+                    var rowSize = self.getCalculateRegionRowSize();
+                    if (o.isNeedFreeze === true) {
+                        var tableHeight = self.bottomRightContainer.element.outerHeight();
+                        return size.height + Math.min(rowSize[1], tableHeight);
+                    } else {
+                        var tableHeight = self.tableContainer.element.outerHeight();
+                        var offset = self.tableContainer.element.offset();
+                        var offsetTop = position.top - offset.top;
+                        var height = tableHeight - offsetTop;
+                        height = Math.min(height, rowSize[0] - offsetTop);
+                        return height;
+                    }
+                };
+                if (j < BI.size(tds) - 1) {
+                    td.resizable({
+                        handles: "e",
+                        minWidth: 15,
+                        helper: "clone",
+                        start: function (event, ui) {
+                            var height = getHeight(ui.size, ui.position);
+                            resizer = BI.createWidget({
+                                type: "bi.layout",
+                                cls: "bi-resizer",
+                                width: ui.size.width,
+                                height: height
+                            });
+
+                            BI.createWidget({
+                                type: "bi.absolute",
+                                element: "body",
+                                items: [{
+                                    el: resizer,
+                                    left: ui.position.left,
+                                    top: ui.position.top
+                                }]
+                            });
+                            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE);
+                        },
+                        resize: function (e, ui) {
+                            var height = getHeight(ui.size, ui.position);
+                            resizer.element.css({"width": ui.size.width + "px", "height": height + "px"});
+                            //o.columnSize[start + j] = ui.size.width;
+                            //self.setColumnSize(o.columnSize);
+                            self.fireEvent(BI.Table.EVENT_TABLE_COLUMN_RESIZE);
+                            e.stopPropagation();
+                            //return false;
+                        },
+                        stop: function (e, ui) {
+                            resizer.destroy();
+                            resizer = null;
+                            o.columnSize[start + j] = ui.size.width - 1;
+                            self.setColumnSize(o.columnSize);
+                            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE);
+                        }
+                    })
+                }
+            })
+        }
+        return frag;
+    },
+
+    _createFooterCells: function (items, columnSize, TDs, Ws) {
+        var o = this.options;
+        var frag = this._createCells(items, columnSize, [], TDs, Ws, 0);
+        return frag;
+    },
+
+    _createColGroup: function (columnSize, store, widgets) {
+        var self = this, o = this.options;
+        this.colgroup = this._colgroup();
+        this.colgroup.element.append(this._createColGroupCells(columnSize, store, widgets));
+        return this.colgroup;
+    },
+
+    _createHeader: function () {
+        var self = this, o = this.options;
+        if (o.header === false) {
+            return;
+        }
+        this.header = this._header();
+        this.header.element.append(this._createHeaderCells(o.header, null, null, this.headerTds, this.headerItems));
+        return this.header;
+    },
+
+    _createFooter: function (columnSize, store, widgets) {
+        var self = this, o = this.options;
+        if (o.footer === false) {
+            return;
+        }
+        this.footer = this._footer();
+        this.footer.element.append(this._createFooterCells(o.footer, null, this.footerTds, this.footerItems));
+        return this.footer;
+    },
+
+    _createBody: function () {
+        var self = this, o = this.options;
+        this.body = this._body();
+        this.body.element.append(this._createCells(o.items, null, null, this.bodyTds, this.bodyItems));
+        return this.body;
+    },
+
+    _createNormalTable: function () {
+        var self = this, o = this.options, table = this._table();
+        this.colgroupTds = {};
+        this.headerTds = {};
+        this.footerTds = {};
+        this.bodyTds = {};
+
+        this.headerItems = {};
+        this.footerItems = {};
+        this.bodyItems = {};
+        var colgroup = this._createColGroup(null, this.colgroupTds);
+        var header = this._createHeader();
+        var footer = this._createFooter();
+        var body = this._createBody();
+
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: table,
+            items: [colgroup, header, footer, body]
+        });
+
+        var w = BI.sum(this.options.columnSize) || undefined;
+        w = this._calculateWidth(w);
+        if (BI.isNumeric(w) && w > 1) {
+            w += o.columnSize.length;
+        }
+        this.tableContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: this._calculateWidth(w),
+            items: [table]
+        });
+
+        this.scrollBottomRight = BI.createWidget({
+            type: "bi.adaptive",
+            width: "100%",
+            height: "100%",
+            cls: "scroll-bottom-right",
+            scrollable: true,
+            items: [this.tableContainer]
+        });
+
+        BI.createWidget({
+            type: "bi.adaptive",
+            cls: "bottom-right",
+            element: this,
+            scrollable: false,
+            items: [this.scrollBottomRight]
+        });
+
+        this._resize = function () {
+            if (self.element.is(":visible")) {
+                self.setColumnSize(o.columnSize);
+            }
+        };
+
+        this._initNormalScroll();
+        BI.Resizers.add(this.getName(), function (e) {
+            if (self.element.is(":visible") && BI.isWindow(e.target)) {
+                self._resize();
+                self.fireEvent(BI.Table.EVENT_TABLE_RESIZE);
+            }
+        });
+        BI.nextTick(function () {
+            if (self.element.is(":visible")) {
+                self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT);
+            }
+        });
+    },
+
+    _initNormalScroll: function () {
+        var self = this;
+        var scrolling, scrollX;
+        this.scrollBottomRight.element.mousewheel(function (event, delta, deltaX, deltaY) {
+            var inf = self._getScrollOffsetAndDur(event);
+            if (deltaY < 0 || deltaY > 0) {
+                var ele = self.scrollBottomRight.element;
+                if (scrolling) {
+                    ele[0].scrollTop = scrolling;
+                }
+
+                scrolling = ele[0].scrollTop - delta * inf.offset;
+                var stopPropagation = false;
+                var st = ele[0].scrollTop;
+                ele[0].scrollTop = scrolling;
+                if (ele[0].scrollTop !== st) {
+                    stopPropagation = true;
+                }
+                ele[0].scrollTop = st;
+                self._animateScrollTo(ele, ele[0].scrollTop, scrolling, inf.dur, "linear", {
+                    onStart: function () {
+                    },
+                    onUpdate: function (top) {
+                        self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, top);
+                    },
+                    onComplete: function () {
+                        self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, scrolling);
+                        scrolling = null;
+                    }
+                });
+                //var scrollTop = self.scrollBottomRight.element[0].scrollTop = self.scrollBottomRight.element[0].scrollTop - delta * offset;
+                //self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, scrollTop);
+                if (stopPropagation === true) {
+                    event.stopPropagation();
+                    return false;
+                }
+            }
+        });
+        var scrollTop = 0, scrollLeft = 0;
+        this.scrollBottomRight.element.scroll(function (e) {
+            var change = false;
+            var scrollElement = self.scrollBottomRight.element;
+            if (scrollElement.scrollTop() != scrollTop) {
+                if (Math.abs(scrollElement.scrollTop() - scrollTop) > 0.1) {
+                    e.stopPropagation();
+                    change = true;
+                }
+                scrollTop = scrollElement.scrollTop();
+            }
+            if (scrollElement.scrollLeft() != scrollLeft) {
+                if (Math.abs(scrollElement.scrollLeft() - scrollLeft) > 0.1) {
+                    e.stopPropagation();
+                    change = true;
+                }
+                scrollLeft = scrollElement.scrollLeft();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL);
+            if (change === true) {
+                e.stopPropagation();
+                //return false;
+            }
+            return false;
+        });
+    },
+
+    _split: function (items) {
+        var o = this.options, left = [], right = [], isRight = this._isRightFreeze();
+        BI.each(items, function (i, rows) {
+            left.push([]);
+            right.push([]);
+            BI.each(rows, function (j, cell) {
+                if (o.freezeCols.contains(j)) {
+                    (isRight ? right : left)[i].push(cell);
+                } else {
+                    (isRight ? left : right)[i].push(cell);
+                }
+            })
+        });
+        return {
+            left: left,
+            right: right
+        }
+    },
+
+    _table: function () {
+        return BI.createWidget({
+            type: "bi.layout",
+            tagName: "table",
+            cls: "table",
+            attribute: {"cellspacing": 0, "cellpadding": 0}
+        });
+    },
+
+    _header: function () {
+        return BI.createWidget({
+            type: "bi.layout",
+            cls: "header",
+            tagName: "thead"
+        });
+    },
+
+    _footer: function () {
+        return BI.createWidget({
+            type: "bi.layout",
+            cls: "footer",
+            tagName: "tfoot"
+        });
+    },
+
+    _body: function () {
+        return BI.createWidget({
+            type: "bi.layout",
+            tagName: "tbody",
+            cls: "body"
+        });
+    },
+
+    _colgroup: function () {
+        return BI.createWidget({
+            type: "bi.layout",
+            tagName: "colgroup"
+        });
+    },
+
+    _init: function () {
+        BI.Table.superclass._init.apply(this, arguments);
+
+        this.populate(this.options.items);
+    },
+
+    setColumnSize: function (columnSize) {
+        var self = this, o = this.options;
+        var isRight = this._isRightFreeze();
+        o.columnSize = columnSize || [];
+        if (o.isNeedFreeze) {
+            var columnLeft = [];
+            var columnRight = [];
+            BI.each(o.columnSize, function (i, size) {
+                if (o.freezeCols.contains(i)) {
+                    isRight ? columnRight.push(size) : columnLeft.push(size);
+                } else {
+                    isRight ? columnLeft.push(size) : columnRight.push(size);
+                }
+            });
+            var topleft = 0, topright = 1, bottomleft = 2, bottomright = 3;
+            var run = function (direction) {
+                var colgroupTds, bodyTds, bodyItems, sizes;
+                switch (direction) {
+                    case topleft:
+                        colgroupTds = self.topLeftColGroupTds;
+                        bodyTds = self.topLeftBodyTds;
+                        bodyItems = self.topLeftBodyItems;
+                        sizes = columnLeft;
+                        break;
+                    case topright:
+                        colgroupTds = self.topRightColGroupTds;
+                        bodyTds = self.topRightBodyTds;
+                        bodyItems = self.topRightBodyItems;
+                        sizes = columnRight;
+                        break;
+                    case bottomleft:
+                        colgroupTds = self.bottomLeftColGroupTds;
+                        bodyTds = self.bottomLeftBodyTds;
+                        bodyItems = self.bottomLeftBodyItems;
+                        sizes = columnLeft;
+                        break;
+                    case bottomright:
+                        colgroupTds = self.bottomRightColGroupTds;
+                        bodyTds = self.bottomRightBodyTds;
+                        bodyItems = self.bottomRightBodyItems;
+                        sizes = columnRight;
+                        break;
+                }
+                BI.each(colgroupTds, function (i, colgroup) {
+                    var width = colgroup.attr("width") | 0;
+                    if (width !== sizes[i]) {
+                        var w = self._calculateWidth(sizes[i]);
+                        colgroup.attr("width", w).css("width", w);
+                        BI.each(bodyTds, function (j, items) {
+                            if (items[i]) {
+                                if (items[i].__mergeCols.length > 1) {
+                                    var wid = 0;
+                                    BI.each(sizes, function (t, s) {
+                                        if (items[i].__mergeCols.contains(t)) {
+                                            wid += s;
+                                        }
+                                    });
+                                    wid = self._calculateWidth(wid);
+                                    if (wid > 1) {
+                                        wid += items[i].__mergeCols.length - 1;
+                                    }
+                                    if (BI.isNumeric(wid)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].attr("width", wid - 1).css("width", wid - 1);
+                                        } else {
+                                            items[i].attr("width", wid).css("width", wid);
+                                        }
+                                    } else {
+                                        items[i].attr("width", "").css("width", "");
+                                    }
+                                } else {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].attr("width", w).css("width", w);
+                                    }
+                                }
+                            }
+                        });
+                        BI.each(bodyItems, function (j, items) {
+                            if (items[i]) {
+                                if (bodyTds[j][i].__mergeCols.length > 1) {
+                                    var wid = 0;
+                                    BI.each(sizes, function (t, s) {
+                                        if (bodyTds[j][i].__mergeCols.contains(t)) {
+                                            wid += s;
+                                        }
+                                    });
+                                    wid = self._calculateWidth(wid);
+                                    if (wid > 1) {
+                                        wid += bodyTds[j][i].__mergeCols.length - 1;
+                                    }
+                                    if (BI.isNumeric(wid)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                        } else {
+                                            items[i].element.attr("width", wid).css("width", wid);
+                                        }
+                                    } else {
+                                        items[i].element.attr("width", "").css("width", "");
+                                    }
+                                } else {
+                                    if (BI.isNumeric(w)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].element.attr("width", w - 1).css("width", w - 1);
+                                        } else {
+                                            items[i].element.attr("width", w).css("width", w);
+                                        }
+                                    } else {
+                                        items[i].element.attr("width", "").css("width", "");
+                                    }
+                                }
+                            }
+                        });
+                    }
+                })
+            };
+            run(topleft);
+            run(topright);
+            run(bottomleft);
+            run(bottomright);
+
+            var lw = 0, rw = 0;
+            this.columnLeft = [];
+            this.columnRight = [];
+            BI.each(o.columnSize, function (i, size) {
+                if (o.freezeCols.contains(i)) {
+                    lw += size;
+                    self[isRight ? "columnRight" : "columnLeft"].push(size);
+                } else {
+                    rw += size;
+                    self[isRight ? "columnLeft" : "columnRight"].push(size);
+                }
+            });
+            lw = this._calculateWidth(lw);
+            rw = this._calculateWidth(rw);
+
+            if (BI.isNumeric(lw)) {
+                lw = BI.parseFloat(lw) + o.freezeCols.length;
+            }
+            if (BI.isNumeric(rw)) {
+                rw = BI.parseFloat(rw) + o.columnSize.length - o.freezeCols.length;
+            }
+            this.topLeftContainer.element.width(isRight ? rw : lw);
+            this.bottomLeftContainer.element.width(isRight ? rw : lw);
+            this.topRightContainer.element.width(isRight ? lw : rw);
+            this.bottomRightContainer.element.width(isRight ? lw : rw);
+            this.scrollTopLeft.element[0].scrollLeft = this.scrollBottomLeft.element[0].scrollLeft;
+            this.scrollTopRight.element[0].scrollLeft = this.scrollBottomRight.element[0].scrollLeft;
+            if (o.isNeedResize && o.isResizeAdapt) {
+                var leftWidth = BI.sum(o.freezeCols, function (i, col) {
+                    return o.columnSize[col] > 1 ? o.columnSize[col] + 1 : o.columnSize[col];
+                });
+                this.partitions.attr("columnSize", isRight ? ['fill', leftWidth] : [leftWidth, 'fill']);
+                this.partitions.resize();
+            }
+        } else {
+            BI.each(this.colgroupTds, function (i, colgroup) {
+                var width = colgroup.attr("width") | 0;
+                if (width !== o.columnSize[i]) {
+                    var w = self._calculateWidth(o.columnSize[i]);
+                    colgroup.attr("width", w).css("width", w);
+                    BI.each(self.bodyTds, function (j, items) {
+                        if (items[i]) {
+                            if (items[i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (items[i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += items[i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (i == BI.size(items) - 1) {
+                                    items[i].attr("width", w - 1).css("width", w - 1);
+                                } else {
+                                    items[i].attr("width", w).css("width", w);
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.headerTds, function (j, items) {
+                        if (items[i]) {
+                            if (items[i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (items[i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += items[i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (i == BI.size(items) - 1) {
+                                    items[i].attr("width", w - 1).css("width", w - 1);
+                                } else {
+                                    items[i].attr("width", w).css("width", w);
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.footerTds, function (j, items) {
+                        if (items[i]) {
+                            if (items[i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (items[i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += items[i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (i == BI.size(items) - 1) {
+                                    items[i].attr("width", w - 1).css("width", w - 1);
+                                } else {
+                                    items[i].attr("width", w).css("width", w);
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.bodyItems, function (j, items) {
+                        if (items[i]) {
+                            if (self.bodyTds[j][i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (self.bodyTds[j][i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += self.bodyTds[j][i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                    } else {
+                                        items[i].element.attr("width", wid).css("width", wid);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (BI.isNumeric(w)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].element.attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.headerItems, function (j, items) {
+                        if (items[i]) {
+                            if (self.headerTds[j][i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (self.headerTds[j][i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += self.headerTds[j][i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                    } else {
+                                        items[i].element.attr("width", wid).css("width", wid);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (BI.isNumeric(w)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].element.attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.footerItems, function (j, items) {
+                        if (items[i]) {
+                            if (self.footerTds[j][i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(o.columnSize, function (t, s) {
+                                    if (self.footerTds[j][i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += self.footerTds[j][i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                    } else {
+                                        items[i].element.attr("width", wid).css("width", wid);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (BI.isNumeric(w)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].element.attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            }
+                        }
+                    });
+                }
+            });
+            var w = this._calculateWidth(BI.sum(o.columnSize));
+            if (w > 1.05) {
+                w += o.columnSize.length;
+            }
+            this.tableContainer.element.width(w);
+        }
+    },
+
+    getColumnSize: function () {
+        return this.options.columnSize;
+    },
+
+    getCalculateColumnSize: function () {
+        var self = this, o = this.options;
+        var columnSize = [];
+        if (o.isNeedFreeze === true) {
+            if (BI.size(this.bottomLeftBodyTds) > 0 || BI.size(this.bottomRightBodyTds) > 0) {
+                if (!BI.any(this.bottomLeftBodyTds, function (i, tds) {
+                        if (!BI.any(tds, function (i, item) {
+                                if (item.__mergeCols.length > 1) {
+                                    return true;
+                                }
+                            })) {
+                            BI.each(tds, function (i, item) {
+                                var width = item.width() / item.__mergeCols.length;
+                                if (i == BI.size(tds) - 1) {
+                                    width++;
+                                }
+                                columnSize.push(width);
+                            });
+                            return true;
+                        }
+                    })) {
+                    BI.each(this.bottomLeftBodyTds[0], function (i, item) {
+                        var width = item.width() / item.__mergeCols.length;
+                        if (i == BI.size(self.bottomLeftBodyTds[0]) - 1) {
+                            width++;
+                        }
+                        columnSize.push(width);
+                    });
+                }
+                if (!BI.any(this.bottomRightBodyTds, function (i, tds) {
+                        if (!BI.any(tds, function (i, item) {
+                                if (item.__mergeCols.length > 1) {
+                                    return true;
+                                }
+                            })) {
+                            BI.each(tds, function (i, item) {
+                                var width = item.width() / item.__mergeCols.length;
+                                if (i == BI.size(tds) - 1) {
+                                    width++;
+                                }
+                                columnSize.push(width);
+                            });
+                            return true;
+                        }
+                    })) {
+                    BI.each(this.bottomRightBodyTds[0], function (i, item) {
+                        var width = item.width() / item.__mergeCols.length;
+                        if (i == BI.size(self.bottomRightBodyTds[0]) - 1) {
+                            width++;
+                        }
+                        columnSize.push(width);
+                    });
+                }
+                return columnSize;
+            }
+            if (!BI.any(this.topLeftBodyTds, function (i, tds) {
+                    if (!BI.any(tds, function (i, item) {
+                            if (item.__mergeCols.length > 1) {
+                                return true;
+                            }
+                        })) {
+                        BI.each(tds, function (i, item) {
+                            var width = item.width() / item.__mergeCols.length;
+                            if (i == BI.size(tds) - 1) {
+                                width++;
+                            }
+                            columnSize.push(width);
+                        });
+                        return true;
+                    }
+                })) {
+                BI.each(this.topLeftBodyTds[BI.size(this.topLeftBodyTds) - 1], function (i, item) {
+                    var width = item.width() / item.__mergeCols.length;
+                    if (i == BI.size(self.topLeftBodyTds[BI.size(self.topLeftBodyTds) - 1]) - 1) {
+                        width++;
+                    }
+                    columnSize.push(width);
+                });
+            }
+            if (!BI.any(this.topRightBodyTds, function (i, tds) {
+                    if (!BI.any(tds, function (i, item) {
+                            if (item.__mergeCols.length > 1) {
+                                return true;
+                            }
+                        })) {
+                        BI.each(tds, function (i, item) {
+                            var width = item.width() / item.__mergeCols.length;
+                            if (i == BI.size(tds) - 1) {
+                                width++;
+                            }
+                            columnSize.push(width);
+                        });
+                        return true;
+                    }
+                })) {
+                BI.each(this.topRightBodyTds[BI.size(this.topRightBodyTds) - 1], function (i, item) {
+                    var width = item.width() / item.__mergeCols.length;
+                    if (i == BI.size(self.topRightBodyTds[BI.size(self.topRightBodyTds) - 1]) - 1) {
+                        width++;
+                    }
+                    columnSize.push(width);
+                });
+            }
+        } else {
+            BI.each(this.headerTds[BI.size(this.headerTds) - 1], function (i, item) {
+                var width = item.width() / item.__mergeCols.length;
+                if (i == BI.size(self.headerTds[BI.size(self.headerTds) - 1]) - 1) {
+                    width++;
+                }
+                columnSize.push(width);
+            });
+        }
+        return columnSize;
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        var self = this, o = this.options;
+        var isRight = this._isRightFreeze();
+        if (o.isNeedFreeze) {
+            var columnLeft = [];
+            var columnRight = [];
+            BI.each(columnSize, function (i, size) {
+                if (o.freezeCols.contains(i)) {
+                    isRight ? columnRight.push(size) : columnLeft.push(size);
+                } else {
+                    isRight ? columnLeft.push(size) : columnRight.push(size);
+                }
+            });
+            var topleft = 0, topright = 1;
+            var run = function (direction) {
+                var colgroupTds, bodyTds, bodyItems, sizes;
+                switch (direction) {
+                    case topleft:
+                        colgroupTds = self.topLeftColGroupTds;
+                        bodyTds = self.topLeftBodyTds;
+                        bodyItems = self.topLeftBodyItems;
+                        sizes = columnLeft;
+                        break;
+                    case topright:
+                        colgroupTds = self.topRightColGroupTds;
+                        bodyTds = self.topRightBodyTds;
+                        bodyItems = self.topRightBodyItems;
+                        sizes = columnRight;
+                        break;
+                }
+                BI.each(colgroupTds, function (i, colgroup) {
+                    var width = colgroup.attr("width") | 0;
+                    if (width !== sizes[i]) {
+                        var w = self._calculateWidth(sizes[i]);
+                        colgroup.attr("width", w).css("width", w);
+                        BI.each(bodyTds, function (j, items) {
+                            if (items[i]) {
+                                if (items[i].__mergeCols.length > 1) {
+                                    var wid = 0;
+                                    BI.each(sizes, function (t, s) {
+                                        if (items[i].__mergeCols.contains(t)) {
+                                            wid += s;
+                                        }
+                                    });
+                                    wid = self._calculateWidth(wid);
+                                    if (wid > 1) {
+                                        wid += items[i].__mergeCols.length - 1;
+                                    }
+                                    if (BI.isNumeric(wid)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].attr("width", wid - 1).css("width", wid - 1);
+                                        } else {
+                                            items[i].attr("width", wid).css("width", wid);
+                                        }
+                                    } else {
+                                        items[i].attr("width", "").css("width", "");
+                                    }
+                                } else {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].attr("width", w).css("width", w);
+                                    }
+                                }
+                            }
+                        });
+                        BI.each(bodyItems, function (j, items) {
+                            if (items[i]) {
+                                if (bodyTds[j][i].__mergeCols.length > 1) {
+                                    var wid = 0;
+                                    BI.each(sizes, function (t, s) {
+                                        if (bodyTds[j][i].__mergeCols.contains(t)) {
+                                            wid += s;
+                                        }
+                                    });
+                                    wid = self._calculateWidth(wid);
+                                    if (wid > 1) {
+                                        wid += bodyTds[j][i].__mergeCols.length - 1;
+                                    }
+                                    if (BI.isNumeric(wid)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                        } else {
+                                            items[i].element.attr("width", wid).css("width", wid);
+                                        }
+                                    } else {
+                                        items[i].element.attr("width", "").css("width", "");
+                                    }
+                                } else {
+                                    if (BI.isNumeric(w)) {
+                                        if (i == BI.size(items) - 1) {
+                                            items[i].element.attr("width", w - 1).css("width", w - 1);
+                                        } else {
+                                            items[i].element.attr("width", w).css("width", w);
+                                        }
+                                    } else {
+                                        items[i].element.attr("width", "").css("width", "");
+                                    }
+                                }
+                            }
+                        });
+                    }
+                })
+            };
+            run(topleft);
+            run(topright);
+
+            var lw = 0, rw = 0;
+            BI.each(columnSize, function (i, size) {
+                if (o.freezeCols.contains(i)) {
+                    lw += size;
+                } else {
+                    rw += size;
+                }
+            });
+            lw = this._calculateWidth(lw);
+            rw = this._calculateWidth(rw);
+
+            if (BI.isNumeric(lw)) {
+                lw = BI.parseFloat(lw) + o.freezeCols.length;
+            }
+            if (BI.isNumeric(rw)) {
+                rw = BI.parseFloat(rw) + columnSize.length - o.freezeCols.length;
+            }
+            this.topLeftContainer.element.width(isRight ? rw : lw);
+            this.topRightContainer.element.width(isRight ? lw : rw);
+            this.scrollTopLeft.element[0].scrollLeft = this.scrollBottomLeft.element[0].scrollLeft;
+            this.scrollTopRight.element[0].scrollLeft = this.scrollBottomRight.element[0].scrollLeft;
+            if (o.isNeedResize && o.isResizeAdapt) {
+                var leftWidth = BI.sum(o.freezeCols, function (i, col) {
+                    return columnSize[col] > 1 ? columnSize[col] + 1 : columnSize[col];
+                });
+                this.partitions.attr("columnSize", isRight ? ['fill', leftWidth] : [leftWidth, 'fill']);
+                this.partitions.resize();
+            }
+        } else {
+            BI.each(this.colgroupTds, function (i, colgroup) {
+                var width = colgroup.attr("width") | 0;
+                if (width !== columnSize[i]) {
+                    var w = self._calculateWidth(columnSize[i]);
+                    colgroup.attr("width", w).css("width", w);
+                    BI.each(self.headerTds, function (j, items) {
+                        if (items[i]) {
+                            if (items[i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(columnSize, function (t, s) {
+                                    if (items[i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += items[i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                    } else {
+                                        items[i].element.attr("width", wid).css("width", wid);
+                                    }
+                                } else {
+                                    items[i].attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (i == BI.size(items) - 1) {
+                                    items[i].attr("width", w - 1).css("width", w - 1);
+                                } else {
+                                    items[i].attr("width", w).css("width", w);
+                                }
+                            }
+                        }
+                    });
+                    BI.each(self.headerItems, function (j, items) {
+                        if (items[i]) {
+                            if (self.headerTds[j][i].__mergeCols.length > 1) {
+                                var wid = 0;
+                                BI.each(columnSize, function (t, s) {
+                                    if (self.headerTds[j][i].__mergeCols.contains(t)) {
+                                        wid += s;
+                                    }
+                                });
+                                wid = self._calculateWidth(wid);
+                                if (wid > 1) {
+                                    wid += self.headerTds[j][i].__mergeCols.length - 1;
+                                }
+                                if (BI.isNumeric(wid)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", wid - 1).css("width", wid - 1);
+                                    } else {
+                                        items[i].element.attr("width", wid).css("width", wid);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            } else {
+                                if (BI.isNumeric(w)) {
+                                    if (i == BI.size(items) - 1) {
+                                        items[i].element.attr("width", w - 1).css("width", w - 1);
+                                    } else {
+                                        items[i].element.attr("width", w).css("width", w);
+                                    }
+                                } else {
+                                    items[i].element.attr("width", "").css("width", "");
+                                }
+                            }
+                        }
+                    });
+                }
+            });
+            var cW = this._calculateWidth(BI.sum(columnSize));
+            if (cW > 1.05) {
+                cW = cW + columnSize.length;
+            }
+            this.tableContainer.element.width(cW);
+        }
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        var self = this, o = this.options;
+        o.regionColumnSize = columnSize;
+        if (o.freezeCols.length === 0) {
+            if (o.isNeedFreeze) {
+                this.partitions.attr("columnSize", this._isRightFreeze() ? ['fill', 0] : [0, 'fill']);
+                this.partitions.resize();
+            } else {
+                this.tableContainer.element.width(columnSize[0]);
+            }
+        } else if (o.freezeCols.length > 0 && o.freezeCols.length < o.columnSize.length) {
+            if (o.isNeedFreeze) {
+                this.partitions.attr("columnSize", columnSize);
+                this.partitions.resize();
+            } else {
+                this.tableContainer.element.width(columnSize[0]);
+            }
+        } else {
+            if (o.isNeedFreeze) {
+                this.partitions.attr("columnSize", this._isRightFreeze() ? [0, 'fill'] : ['fill', 0]);
+                this.partitions.resize();
+            } else {
+                this.tableContainer.element.width(columnSize[0]);
+            }
+        }
+    },
+
+    getRegionColumnSize: function () {
+        return this.options.regionColumnSize;
+    },
+
+    getCalculateRegionColumnSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return [this.scrollBottomLeft.element.width(), this.scrollBottomRight.element.width()];
+        }
+        return [this.scrollBottomRight.element.width()];
+    },
+
+    getCalculateRegionRowSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return [this.scrollTopRight.element.height(), this.scrollBottomRight.element.height()];
+        }
+        return [this.scrollBottomRight.element.height()];
+    },
+
+    getClientRegionColumnSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return [this.scrollBottomLeft.element[0].clientWidth, this.scrollBottomRight.element[0].clientWidth];
+        }
+        return [this.scrollBottomRight.element[0].clientWidth];
+    },
+
+    getClientRegionRowSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return [this.scrollBottomLeft.element[0].clientHeight, this.scrollBottomRight.element[0].clientHeight];
+        }
+        return [this.scrollBottomRight.element[0].clientHeight];
+    },
+
+    getScrollRegionColumnSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return [this.scrollBottomLeft.element[0].scrollWidth, this.scrollBottomRight.element[0].scrollWidth];
+        }
+        return [this.scrollBottomRight.element[0].scrollWidth];
+    },
+
+    getScrollRegionRowSize: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            if (o.freezeCols.length < o.columnSize.length) {
+                return [this.scrollTopRight.element[0].scrollHeight, this.scrollBottomRight.element[0].scrollHeight];
+            } else {
+                return [this.scrollTopLeft.element[0].scrollHeight, this.scrollBottomLeft.element[0].scrollHeight];
+            }
+        }
+        return [this.scrollBottomRight.element[0].scrollHeight];
+    },
+
+    hasVerticalScroll: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return this.scrollBottomRight.element.hasVerticalScroll() || this.scrollBottomLeft.element.hasVerticalScroll();
+        }
+        return this.scrollBottomRight.element.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            if (this.scrollBottomRight.element[0].scrollTop !== scrollTop) {
+                this.scrollBottomRight.element[0].scrollTop = scrollTop;
+            }
+            if (this.scrollBottomLeft.element[0].scrollTop !== scrollTop) {
+                this.scrollBottomLeft.element[0].scrollTop = scrollTop;
+            }
+        } else {
+            if (this.scrollBottomRight.element[0].scrollTop !== scrollTop) {
+                this.scrollBottomRight.element[0].scrollTop = scrollTop;
+            }
+        }
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            if (this.scrollBottomLeft.element[0].scrollLeft !== scrollLeft) {
+                this.scrollBottomLeft.element[0].scrollLeft = scrollLeft;
+            }
+            if (this.scrollTopLeft.element[0].scrollLeft !== scrollLeft) {
+                this.scrollTopLeft.element[0].scrollLeft = scrollLeft;
+            }
+        } else {
+            if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) {
+                this.scrollBottomRight.element[0].scrollLeft = scrollLeft;
+            }
+        }
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) {
+                this.scrollBottomRight.element[0].scrollLeft = scrollLeft;
+            }
+            if (this.scrollTopRight.element[0].scrollLeft !== scrollLeft) {
+                this.scrollTopRight.element[0].scrollLeft = scrollLeft;
+            }
+        } else {
+            if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) {
+                this.scrollBottomRight.element[0].scrollLeft = scrollLeft;
+            }
+        }
+    },
+
+    getVerticalScroll: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return this.scrollBottomRight.element[0].scrollTop || this.scrollBottomLeft.element[0].scrollTop;
+        }
+        return this.scrollBottomRight.element[0].scrollTop;
+    },
+
+    getLeftHorizontalScroll: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return this.scrollBottomLeft.element[0].scrollLeft;
+        }
+        return this.scrollBottomRight.element[0].scrollLeft;
+    },
+
+    getRightHorizontalScroll: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return this.scrollBottomRight.element[0].scrollLeft;
+        }
+        return this.scrollBottomRight.element[0].scrollLeft;
+    },
+
+    getColumns: function () {
+        var o = this.options;
+        if (o.isNeedFreeze) {
+            return {
+                topLeft: this.topLeftBodyItems,
+                topRight: this.topRightBodyItems,
+                bottomLeft: this.bottomLeftBodyItems,
+                bottomRight: this.bottomRightBodyItems
+            }
+        } else {
+            return {
+                header: this.headerItems,
+                body: this.bodyItems,
+                footer: this.footerItems
+            }
+        }
+    },
+
+    populate: function (items, header) {
+        this.options.items = items || [];
+        if (header) {
+            this.options.header = header;
+        }
+        this.empty();
+        if (this.options.isNeedFreeze) {
+            this._createFreezeTable();
+        } else {
+            this._createNormalTable();
+        }
+    },
+
+    empty: function () {
+        BI.Resizers.remove(this.getName());
+        BI.Table.superclass.empty.apply(this, arguments);
+    },
+
+    destroy: function () {
+        BI.Table.superclass.destroy.apply(this, arguments);
+    }
+})
+;
+BI.Table.EVENT_TABLE_AFTER_INIT = "EVENT_TABLE_AFTER_INIT";
+BI.Table.EVENT_TABLE_RESIZE = "EVENT_TABLE_RESIZE";
+BI.Table.EVENT_TABLE_SCROLL = "EVENT_TABLE_SCROLL";
+BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE = "EVENT_TABLE_BEFORE_COLUMN_RESIZE";
+BI.Table.EVENT_TABLE_COLUMN_RESIZE = "EVENT_TABLE_COLUMN_RESIZE";
+BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE = "EVENT_TABLE_AFTER_COLUMN_RESIZE";
+
+BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE = "EVENT_TABLE_BEFORE_REGION_RESIZE";
+BI.Table.EVENT_TABLE_REGION_RESIZE = "EVENT_TABLE_REGION_RESIZE";
+BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE = "EVENT_TABLE_AFTER_REGION_RESIZE";
+$.shortcut("bi.table_view", BI.Table);
+/**
+ *
+ * 表格单元格
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.ResizableTableCell
+ * @extends BI.Widget
+ */
+BI.ResizableTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ResizableTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-resizable-table-cell",
+            cell: {},
+            start: BI.emptyFn,
+            resize: BI.emptyFn,
+            stop: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.ResizableTableCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.cell = BI.createWidget(BI.extend({type: "bi.label"}, o.cell, {width: o.width, height: o.height}));
+
+        var startDrag = false;
+        var size = 0, offset = 0, defaultSize = o.width;
+        var mouseMoveTracker = new BI.MouseMoveTracker(function (deltaX, deltaY) {
+            if (mouseMoveTracker.isDragging()) {
+                startDrag = true;
+                offset += deltaX;
+                size = BI.clamp(defaultSize + offset, 15, Number.MAX_VALUE);
+                self.handler.element.addClass("dragging");
+                o.resize(size);
+            }
+        }, function () {
+            if (startDrag === true) {
+                size = BI.clamp(size, 15, Number.MAX_VALUE);
+                o.stop(size);
+                size = 0;
+                offset = 0;
+                defaultSize = o.width;
+                self.handler.element.removeClass("dragging");
+                startDrag = false;
+            }
+            mouseMoveTracker.releaseMouseMoves();
+        }, document);
+        this.handler = BI.createWidget({
+            type: "bi.absolute",
+            cls: "resizable-table-cell-resizer-container",
+            width: 6,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    cls: "resizable-table-cell-resizer-knob",
+                    width: 4
+                },
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.handler.element.on("mousedown", function (event) {
+            defaultSize = o.width;
+            mouseMoveTracker.captureMouseMoves(event);
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.cell,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.handler,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    setWidth: function (width) {
+        BI.ResizableTableCell.superclass.setWidth.apply(this, arguments);
+        var o = this.options;
+        this.cell.setWidth(o.width);
+    },
+
+    setHeight: function (height) {
+        BI.ResizableTableCell.superclass.setHeight.apply(this, arguments);
+        var o = this.options;
+        this.cell.setHeight(o.height);
+    }
+});
+$.shortcut("bi.resizable_table_cell", BI.ResizableTableCell);/**
+ *
+ * 可调整列宽的grid表格
+ *
+ * Created by GUY on 2016/1/12.
+ * @class BI.ResizableTable
+ * @extends BI.Widget
+ */
+BI.ResizableTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ResizableTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-resizable-table",
+            el: {
+                type: "bi.grid_table"
+            },
+            isNeedFreeze: false,
+            isNeedResize: true,
+            isResizeAdapt: false,
+            headerRowSize: 25,
+            rowSize: 25,
+            isNeedMerge: true,//是否需要合并单元格
+            mergeCols: [],
+            mergeRule: BI.emptyFn,
+            columnSize: [],
+            freezeCols: [],
+            header: [],
+            items: [],
+            regionColumnSize: []
+        })
+    },
+
+    _init: function () {
+        BI.ResizableTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.resizer = BI.createWidget({
+            type: "bi.layout",
+            cls: "resizable-table-resizer",
+            invisible: true,
+            width: 2
+        });
+        this.regionResizerHandler = this._createResizerHandler();
+        this.table = BI.createWidget(o.el, {
+            type: "bi.grid_table",
+            element: this,
+            width: o.width,
+            height: o.height,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+            columnSize: o.columnSize,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: BI.bind(this._mergeRule, this),
+
+            header: this._formatHeader(o.header),
+            items: o.items,
+            regionColumnSize: o.regionColumnSize
+        });
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.regionResizerHandler,
+                left: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.resizer,
+                left: 0,
+                top: 0
+            }]
+        });
+        this._populate();
+    },
+
+    _mergeRule: function (row1, row2) {
+        var o = this.options;
+        if (row1.type === "bi.resizable_table_cell") {
+            row1 = row1.cell;
+        }
+        if (row2.type === "bi.resizable_table_cell") {
+            row2 = row2.cell;
+        }
+        return o.mergeRule(row1, row2);
+    },
+
+    _createResizerHandler: function () {
+        var self = this, o = this.options;
+        var regionResizerHandler = BI.createWidget({
+            type: "bi.absolute",
+            cls: "resizable-table-region-resizer",
+            invisible: true,
+            width: 6,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    width: 2,
+                    cls: "resizable-table-region-resizer-knob"
+                },
+                left: 2,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        var size = 0, offset = 0, defaultSize = 0, start = false;
+        var mouseMoveTracker = new BI.MouseMoveTracker(function (deltaX, deltaY) {
+            if (mouseMoveTracker.isDragging()) {
+                start = true;
+                offset += deltaX;
+                size = BI.clamp(defaultSize + offset, 15, o.width - 15);
+
+                self.regionResizerHandler.element.addClass("dragging");
+                self._setRegionResizerHandlerPosition(size - 3, 0);
+            }
+
+        }, function () {
+            if (start === true) {
+                o.regionColumnSize[0] = BI.clamp(size, 15, o.width - 15);
+                self.table.setRegionColumnSize(o.regionColumnSize);
+                if (o.isResizeAdapt === true) {
+                    var freezeColumnSize = self._getFreezeColumnSize();
+                    o.columnSize[self._getFreezeColLength() - 1] += o.regionColumnSize[0] - freezeColumnSize;
+                    self.table.setColumnSize(o.columnSize);
+                }
+                self.table.populate();
+                self._populate();
+                self.regionResizerHandler.element.removeClass("dragging");
+                self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE);
+                start = false;
+            }
+            mouseMoveTracker.releaseMouseMoves();
+        }, document);
+        regionResizerHandler.element.on("mousedown", function (event) {
+            defaultSize = size = self._getRegionSize();
+            offset = 0;
+            self._setResizerPosition(0, 0);
+            mouseMoveTracker.captureMouseMoves(event);
+        });
+        return regionResizerHandler;
+    },
+
+    _setResizerPosition: function (left, top) {
+        this.resizer.element.css({
+            left: left + "px",
+            top: top + "px"
+        });
+    },
+
+    _setRegionResizerHandlerPosition: function (left, top) {
+        this.regionResizerHandler.element.css({
+            left: left + "px",
+            top: top + "px"
+        });
+    },
+
+    _getRegionSize: function () {
+        var o = this.options;
+        var regionSize = o.regionColumnSize[0] || 0;
+        if (o.isNeedFreeze === false || o.freezeCols.length === 0) {
+            return 0;
+        }
+        if (!regionSize) {
+            BI.each(o.freezeCols, function (i, col) {
+                regionSize += o.columnSize[col];
+            });
+        }
+        return regionSize;
+    },
+
+    _getRegionRowSize: function () {
+        var o = this.options;
+        return [o.header.length * o.headerRowSize,
+            Math.min(o.height - o.header.length * o.headerRowSize, o.items.length * o.rowSize)];
+    },
+
+    _getFreezeColLength: function () {
+        return this.options.freezeCols.length;
+    },
+
+    _getFreezeColumnSize: function () {
+        var columnSize = this.options.columnSize;
+        var sum = 0;
+        for (var i = 0, len = this._getFreezeColLength(); i < len; i++) {
+            sum += columnSize[i];
+        }
+        return sum;
+    },
+
+    _getResizerLeft: function (j) {
+        var left = 0;
+        var columnSize = this.options.columnSize;
+        var freezeColLength = this._getFreezeColLength();
+        for (var i = (j >= freezeColLength ? freezeColLength : 0); i < j; i++) {
+            left += columnSize[i] || 0;
+        }
+        if (j >= freezeColLength) {
+            left += this.table.getRegionSize();
+            left -= this.table.getRightHorizontalScroll();
+        } else {
+            left -= this.table.getLeftHorizontalScroll();
+        }
+        return left;
+    },
+
+    _formatHeader: function (header) {
+        var self = this, o = this.options;
+        var result = [];
+        var resize = function (j, size) {
+            self.resizer.setVisible(true);
+            var height = o.headerRowSize + self._getRegionRowSize()[1];
+            self.resizer.setHeight(height);
+
+            self._setResizerPosition(self._getResizerLeft(j) + size, (o.header.length - 1) * o.headerRowSize);
+        };
+        var stop = function (j, size) {
+            self.resizer.setVisible(false);
+            o.columnSize[j] = size;
+            self.table.setColumnSize(o.columnSize);
+            self.table.populate();
+            self._populate();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE);
+        };
+        BI.each(header, function (i, cols) {
+            if (i === header.length - 1) {
+                result[i] = [];
+                BI.each(cols, function (j, col) {
+                    if (j === self._getFreezeColLength() - 1 || j === cols.length - 1) {
+                        result[i][j] = col;
+                    } else {
+                        result[i][j] = {
+                            type: "bi.resizable_table_cell",
+                            cell: col,
+                            resize: BI.bind(resize, null, j),
+                            stop: BI.bind(stop, null, j)
+                        };
+                        if (o.isNeedMerge) {
+                            var r = i;
+                            while (r > 0 && self._mergeRule(result[r][j], result[r - 1][j])) {
+                                result[r - 1][j] = {
+                                    type: "bi.resizable_table_cell",
+                                    cell: result[r - 1][j],
+                                    resize: BI.bind(resize, null, j),
+                                    stop: BI.bind(stop, null, j)
+                                };
+                                r--;
+                            }
+                        }
+                    }
+                });
+            } else {
+                result.push(cols);
+            }
+        });
+        return result;
+    },
+
+    _populate: function () {
+        var o = this.options;
+        var regionSize = this._getRegionSize();
+        if (regionSize > 0) {
+            this.regionResizerHandler.setVisible(true);
+            this._setRegionResizerHandlerPosition(regionSize - 3, 0);
+        } else {
+            this.regionResizerHandler.setVisible(false);
+        }
+    },
+
+    setWidth: function (width) {
+        BI.ResizableTable.superclass.setWidth.apply(this, arguments);
+        this.table.setWidth(width)
+    },
+
+    setHeight: function (height) {
+        BI.ResizableTable.superclass.setHeight.apply(this, arguments);
+        this.table.setHeight(height);
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.options.regionColumnSize = columnSize;
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    attr: function () {
+        BI.ResizableTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    restore: function () {
+        this.table.restore();
+    },
+
+    populate: function (items, header) {
+        if (items) {
+            this.options.items = items;
+        }
+        if (header) {
+            this.options.header = header;
+            if (this.options.isNeedResize) {
+                header = this._formatHeader(header);
+            }
+        }
+        this.table.populate(items, header);
+        this._populate();
+    }
+});
+
+$.shortcut("bi.resizable_table", BI.ResizableTable);/**
+ * guy
+ * 异步树
+ * @class BI.TreeView
+ * @extends BI.Pane
+ */
+BI.TreeView = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TreeView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree",
+            paras: {},
+            itemsCreator: BI.emptyFn
+        })
+    },
+    _init: function () {
+        BI.TreeView.superclass._init.apply(this, arguments);
+
+        this._stop = false;
+        this.container = BI.createWidget();
+
+        this._createTree();
+        this.tip = BI.createWidget({
+            type: "bi.loading_bar",
+            invisible: true,
+            handler: BI.bind(this._loadMore, this)
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrollable: true,
+            scrolly: false,
+            element: this,
+            items: [this.container, this.tip]
+        });
+
+    },
+
+    _createTree: function () {
+        this.id = "bi-tree" + BI.UUID();
+        if (this.nodes) {
+            this.nodes.destroy();
+        }
+        if (this.tree) {
+            this.tree.destroy();
+        }
+        this.tree = BI.createWidget({
+            type: "bi.layout",
+            element: "<ul id='" + this.id + "' class='ztree'></ul>"
+        });
+        BI.createWidget({
+            type: "bi.default",
+            element: this.container,
+            items: [this.tree]
+        });
+    },
+
+    //选择节点触发方法
+    _selectTreeNode: function (treeId, treeNode) {
+        this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, treeNode, this);
+        this.fireEvent(BI.TreeView.EVENT_CHANGE, treeNode, this);
+    },
+
+    //配置属性
+    _configSetting: function () {
+        var paras = this.options.paras;
+        var self = this;
+        var setting = {
+            async: {
+                enable: true,
+                url: getUrl,
+                autoParam: ["id", "name"],
+                otherParam: BI.cjkEncodeDO(paras)
+            },
+            check: {
+                enable: true
+            },
+            data: {
+                key: {
+                    title: "title",
+                    name: "text"
+                },
+                simpleData: {
+                    enable: true
+                }
+            },
+            view: {
+                showIcon: false,
+                expandSpeed: "",
+                nameIsHTML: true,
+                dblClickExpand: false
+            },
+            callback: {
+                beforeExpand: beforeExpand,
+                onAsyncSuccess: onAsyncSuccess,
+                onAsyncError: onAsyncError,
+                beforeCheck: beforeCheck,
+                onCheck: onCheck,
+                onExpand: onExpand,
+                onCollapse: onCollapse,
+                onClick: onClick
+            }
+        };
+        var className = "dark", perTime = 100;
+
+        function onClick(event, treeId, treeNode) {
+            self.nodes.checkNode(treeNode, !treeNode.checked, true, true);
+        }
+
+        function getUrl(treeId, treeNode) {
+            var parentNode = self._getParentValues(treeNode);
+            treeNode.times = treeNode.times || 1;
+            var param = "id=" + treeNode.id
+                + "&times=" + (treeNode.times++)
+                + "&parent_values= " + window.encodeURIComponent(BI.jsonEncode(parentNode))
+                + "&check_state=" + window.encodeURIComponent(BI.jsonEncode(treeNode.getCheckStatus()));
+
+            return BI.servletURL + '?op=' + self.options.op + '&cmd=' + self.options.cmd + "&" + param;
+        }
+
+        function beforeExpand(treeId, treeNode) {
+            if (!treeNode.isAjaxing) {
+                if (!treeNode.children) {
+                    treeNode.times = 1;
+                    ajaxGetNodes(treeNode, "refresh");
+                }
+                return true;
+            } else {
+                BI.Msg.toast("Please Wait。", "warning");
+                return false;
+            }
+        }
+
+        function onAsyncSuccess(event, treeId, treeNode, msg) {
+            treeNode.halfCheck = false;
+            if (!msg || msg.length === 0 || /^<html>[\s,\S]*<\/html>$/gi.test(msg) || self._stop) {
+                return;
+            }
+            var zTree = self.nodes;
+            var totalCount = treeNode.count || 0;
+
+            //尝试去获取下一组节点,若获取值为空数组,表示获取完成
+            // TODO by GUY
+            if (treeNode.children.length > totalCount) {
+                treeNode.count = treeNode.children.length;
+                BI.delay(function () {
+                    ajaxGetNodes(treeNode);
+                }, perTime);
+            } else {
+                //treeNode.icon = "";
+                zTree.updateNode(treeNode);
+                zTree.selectNode(treeNode.children[0]);
+                //className = (className === "dark" ? "":"dark");
+            }
+        }
+
+        function onAsyncError(event, treeId, treeNode, XMLHttpRequest, textStatus, errorThrown) {
+            var zTree = self.nodes;
+            BI.Msg.toast("Error!", "warning");
+            //treeNode.icon = "";
+            //zTree.updateNode(treeNode);
+        }
+
+        function ajaxGetNodes(treeNode, reloadType) {
+            var zTree = self.nodes;
+            if (reloadType == "refresh") {
+                //treeNode.icon = FR.servletURL +"?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/loading.gif";
+                zTree.updateNode(treeNode);
+            }
+            zTree.reAsyncChildNodes(treeNode, reloadType, true);
+        }
+
+        function beforeCheck(treeId, treeNode) {
+            treeNode.halfCheck = false;
+            if (treeNode.checked === true) {
+                //将展开的节点halfCheck设为false,解决展开节点存在halfCheck=true的情况 guy
+                //所有的半选状态都需要取消halfCheck=true的情况
+                function track(children) {
+                    BI.each(children, function (i, ch) {
+                        if (ch.halfCheck === true) {
+                            ch.halfCheck = false;
+                            track(ch.children);
+                        }
+                    })
+                }
+
+                track(treeNode.children);
+                var treeObj = self.nodes;
+                var nodes = treeObj.getSelectedNodes();
+                $.each(nodes, function (index, node) {
+                    node.halfCheck = false;
+                })
+            }
+        }
+
+        function onCheck(event, treeId, treeNode) {
+            self._selectTreeNode(treeId, treeNode);
+        }
+
+        function onExpand(event, treeId, treeNode) {
+            treeNode.halfCheck = false;
+        }
+
+        function onCollapse(event, treeId, treeNode) {
+        }
+
+        return setting;
+    },
+
+    _getParentValues: function (treeNode) {
+        if (!treeNode.getParentNode()) {
+            return [];
+        }
+        var parentNode = treeNode.getParentNode();
+        var result = this._getParentValues(parentNode);
+        result = result.concat([this._getNodeValue(parentNode)]);
+        return result;
+    },
+
+    _getNodeValue: function (node) {
+        //去除标红
+        return node.value || node.text.replace(/<[^>]+>/g, "");
+    },
+
+    //获取半选框值
+    _getHalfSelectedValues: function (map, node) {
+        var self = this;
+        var checkState = node.getCheckStatus();
+        //将未选的去掉
+        if (checkState.checked === false && checkState.half === false) {
+            return;
+        }
+        //如果节点已展开,并且是半选
+        if (BI.isNotEmptyArray(node.children) && checkState.half === true) {
+            var children = node.children;
+            BI.each(children, function (i, ch) {
+                self._getHalfSelectedValues(map, ch);
+            });
+            return;
+        }
+        var parent = node.parentValues || self._getParentValues(node);
+        var path = parent.concat(this._getNodeValue(node));
+        if (BI.isNotEmptyArray(node.children) || checkState.half === false) {
+            this._buildTree(map, path);
+            return;
+        }
+        var storeValues = BI.deepClone(this.options.paras.selected_values);
+        var treeNode = this._getTree(storeValues, path);
+        this._addTreeNode(map, parent, this._getNodeValue(node), treeNode);
+    },
+
+    _getTree: function (map, values) {
+        var cur = map;
+        BI.any(values, function (i, value) {
+            if (cur[value] == null) {
+                return true;
+            }
+            cur = cur[value];
+        });
+        return cur;
+    },
+
+    _addTreeNode: function (map, values, key, value) {
+        var cur = map;
+        BI.each(values, function (i, value) {
+            if (cur[value] == null) {
+                cur[value] = {};
+            }
+            cur = cur[value];
+        });
+        cur[key] = value;
+    },
+
+    //构造树节点
+    _buildTree: function (map, values) {
+        var cur = map;
+        BI.each(values, function (i, value) {
+            if (cur[value] == null) {
+                cur[value] = {};
+            }
+            cur = cur[value];
+        })
+    },
+
+    //获取选中的值
+    _getSelectedValues: function () {
+        var self = this;
+        var hashMap = {};
+        var rootNoots = this.nodes.getNodes();
+        track(rootNoots);
+        function track(nodes) {
+            BI.each(nodes, function (i, node) {
+                var checkState = node.getCheckStatus();
+                if (checkState.checked === true || checkState.half === true) {
+                    if (checkState.half === true) {
+                        self._getHalfSelectedValues(hashMap, node);
+                    } else {
+                        var parentValues = node.parentValues || self._getParentValues(node);
+                        var values = parentValues.concat([self._getNodeValue(node)]);
+                        self._buildTree(hashMap, values);
+                    }
+                }
+            })
+        }
+
+        return hashMap;
+    },
+
+    //处理节点
+    _dealWidthNodes: function (nodes) {
+        var self = this, o = this.options;
+        //处理标红
+        if (BI.isKey(o.paras.keyword)) {
+            var keyword = o.paras.keyword;
+            var ns = BI.Tree.transformToArrayFormat(nodes);
+            BI.each(ns, function (i, n) {
+                n.text = $("<div>").__textKeywordMarked__(n.text, keyword, n.py).html();
+            });
+        }
+        return nodes;
+    },
+
+    _loadMore: function () {
+        var self = this, o = this.options;
+        this.tip.setLoading();
+        var op = BI.extend({}, o.paras, {
+            times: ++this.times
+        });
+        o.itemsCreator(op, function (res) {
+            if (self._stop === true) {
+                return;
+            }
+            var hasNext = !!res.hasNext, nodes = res.items || [];
+
+            if (!hasNext) {
+                self.tip.setEnd();
+            } else {
+                self.tip.setLoaded();
+            }
+            if (nodes.length > 0) {
+                self.nodes.addNodes(null, self._dealWidthNodes(nodes));
+            }
+        });
+    },
+
+    //生成树内部方法
+    _initTree: function (setting) {
+        var self = this, o = this.options;
+        self.fireEvent(BI.Events.INIT);
+        this.times = 1;
+        var tree = this.tree;
+        tree.empty();
+        this.loading();
+        this.tip.setVisible(false);
+        var callback = function (nodes) {
+            if (self._stop === true) {
+                return;
+            }
+            self.nodes = $.fn.zTree.init(tree.element, setting, nodes);
+        };
+        var op = BI.extend({}, o.paras, {
+            times: 1,
+            type: BICst.TREE.TREE_REQ_TYPE.INIT_DATA
+        });
+
+        o.itemsCreator(op, function (res) {
+            if (self._stop === true) {
+                return;
+            }
+            var hasNext = !!res.hasNext, nodes = res.items || [];
+            if (nodes.length > 0) {
+                callback(self._dealWidthNodes(nodes));
+            }
+            self.setTipVisible(nodes.length <= 0);
+            self.loaded();
+            if (!hasNext) {
+                self.tip.invisible();
+            } else {
+                self.tip.setLoaded();
+            }
+            op.times === 1 && self.fireEvent(BI.Events.AFTERINIT);
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes, setting) {
+        var setting = setting || {
+                async: {
+                    enable: false
+                },
+                check: {
+                    enable: false
+                },
+                data: {
+                    key: {
+                        title: "title",
+                        name: "text"
+                    },
+                    simpleData: {
+                        enable: true
+                    }
+                },
+                view: {
+                    showIcon: false,
+                    expandSpeed: ""
+                },
+                callback: {}
+            };
+        this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes);
+    },
+
+    start: function () {
+        this._stop = false;
+    },
+
+    stop: function () {
+        this._stop = true;
+    },
+
+    //生成树方法
+    stroke: function (config) {
+        delete this.options.keyword;
+        BI.extend(this.options.paras, config);
+        var setting = this._configSetting();
+        this._createTree();
+        this.start();
+        this._initTree(setting);
+    },
+
+    populate: function () {
+        this.stroke.apply(this, arguments);
+    },
+
+    hasChecked: function () {
+        var treeObj = this.nodes;
+        return treeObj.getCheckedNodes(true).length > 0;
+    },
+
+    checkAll: function (checked) {
+        this.nodes && this.nodes.checkAllNodes(checked);
+    },
+
+    expandAll: function (flag) {
+        this.nodes && this.nodes.expandAll(flag);
+    },
+
+    setValue: function (value, param) {
+        this.options.paras.selected_values = value || {};
+        this.selected_values = BI.deepClone(value) || {};
+        this.checkAll(false);
+        this.updateValue(value, param);
+        this.refresh();
+    },
+
+    updateValue: function (values, param) {
+        if (!this.nodes) {
+            return;
+        }
+        param || (param = "value");
+        var treeObj = this.nodes;
+        BI.each(values, function (v, op) {
+            var nodes = treeObj.getNodesByParam(param, v, null);
+            BI.each(nodes, function (j, node) {
+                BI.extend(node, {checked: true}, op);
+                treeObj.updateNode(node);
+            })
+        });
+    },
+
+    refresh: function () {
+        this.nodes && this.nodes.refresh();
+    },
+
+    getValue: function () {
+        if (!this.nodes) {
+            return null;
+        }
+        return this._getSelectedValues();
+    },
+
+    empty: function () {
+        BI.isNotNull(this.nodes) && this.nodes.destroy();
+    },
+
+    destroy: function () {
+        this.stop();
+        this.nodes && this.nodes.destroy();
+        BI.TreeView.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.extend(BI.TreeView, {
+    REQ_TYPE_INIT_DATA: 1,
+    REQ_TYPE_ADJUST_DATA: 2,
+    REQ_TYPE_CALCULATE_SELECT_DATA: 3,
+    REQ_TYPE_SELECTED_DATA: 4
+});
+
+BI.TreeView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.TreeView.EVENT_INIT = BI.Events.INIT;
+BI.TreeView.EVENT_AFTERINIT = BI.Events.AFTERINIT;
+
+$.shortcut("bi.tree", BI.TreeView);/**
+ * guy
+ * 同步树
+ * @class BI.SyncTree
+ * @extends BI.TreeView
+ */
+BI.SyncTree = BI.inherit(BI.TreeView, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SyncTree.superclass._defaultConfig.apply(this, arguments), {})
+    },
+    _init: function () {
+        BI.SyncTree.superclass._init.apply(this, arguments);
+    },
+
+    //配置属性
+    _configSetting: function () {
+        var paras = this.options.paras;
+        var self = this;
+        var setting = {
+            async: {
+                enable: false,
+                otherParam: BI.cjkEncodeDO(paras)
+            },
+            check: {
+                enable: true
+            },
+            data: {
+                key: {
+                    title: "title",
+                    name: "text"
+                },
+                simpleData: {
+                    enable: true
+                }
+            },
+            view: {
+                showIcon: false,
+                expandSpeed: "",
+                nameIsHTML: true,
+                dblClickExpand: false
+            },
+            callback: {
+                beforeCheck: beforeCheck,
+                onCheck: onCheck,
+                beforeExpand: beforeExpand,
+                onExpand: onExpand,
+                onCollapse: onCollapse,
+                onClick: onClick
+            }
+        };
+
+        function onClick(event, treeId, treeNode) {
+            var zTree = $.fn.zTree.getZTreeObj(treeId);
+            zTree.checkNode(treeNode, !treeNode.checked, true, true);
+        }
+
+        function beforeCheck(treeId, treeNode) {
+            treeNode.halfCheck = false;
+            if (treeNode.checked === true) {
+                //将展开的节点halfCheck设为false,解决展开节点存在halfCheck=true的情况 guy
+                //所有的半选状态都需要取消halfCheck=true的情况
+                function track(children) {
+                    BI.each(children, function (i, ch) {
+                        if (ch.halfCheck === true) {
+                            ch.halfCheck = false;
+                            track(ch.children);
+                        }
+                    })
+                }
+
+                track(treeNode.children);
+
+                var treeObj = $.fn.zTree.getZTreeObj(treeId);
+                var nodes = treeObj.getSelectedNodes();
+                BI.each(nodes, function (index, node) {
+                    node.halfCheck = false;
+                })
+            }
+        }
+
+        function beforeExpand(treeId, treeNode) {
+            self._expandNode(treeId, treeNode);
+        }
+
+        function onCheck(event, treeId, treeNode) {
+            self._selectTreeNode(treeId, treeNode);
+        }
+
+        function onExpand(event, treeId, treeNode) {
+            treeNode.halfCheck = false;
+        }
+
+        function onCollapse(event, treeId, treeNode) {
+            treeNode.halfCheck = false;
+        }
+
+        return setting;
+    },
+
+    _selectTreeNode: function (treeId, treeNode) {
+        var self = this, o = this.options;
+        var parent_values = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode));
+        var name = this._getNodeValue(treeNode)
+//        var values = parent_values.concat([name]);
+        if (treeNode.checked === true) {
+        } else {
+            var tNode = treeNode;
+            var pNode = this._getTree(this.selected_values, parent_values);
+            if (BI.isNotNull(pNode[name])) {
+                delete pNode[name];
+            }
+            while (tNode != null && BI.isEmpty(pNode)) {
+                parent_values = parent_values.slice(0, parent_values.length - 1);
+                tNode = tNode.getParentNode();
+                if (tNode != null) {
+                    pNode = this._getTree(this.selected_values, parent_values);
+                    name = this._getNodeValue(tNode);
+                    delete pNode[name];
+                }
+            }
+        }
+        BI.SyncTree.superclass._selectTreeNode.apply(self, arguments);
+    },
+
+    //展开节点
+    _expandNode: function (treeId, treeNode) {
+        var self = this, o = this.options;
+        var parentValues = treeNode.parentValues || self._getParentValues(treeNode);
+        var op = BI.extend({}, o.paras, {
+            "id": treeNode.id,
+            "times": 1,
+            "parent_values": parentValues.concat(this._getNodeValue(treeNode)),
+            "check_state": treeNode.getCheckStatus()
+        });
+        var complete = function (d) {
+            var nodes = d.items || [];
+            if (nodes.length > 0) {
+                callback(self._dealWidthNodes(nodes), !!d.hasNext);
+            }
+        };
+        var times = 1;
+
+        function callback(nodes, hasNext) {
+            self.nodes.addNodes(treeNode, nodes);
+
+            if (hasNext === true) {
+                BI.delay(function () {
+                    times++;
+                    op.times = times;
+                    o.itemsCreator(op, complete);
+                }, 100);
+            }
+        }
+
+        if (!treeNode.children) {
+            o.itemsCreator(op, complete)
+        }
+    },
+
+    _joinTree: function (map, values, isLast) {
+        var cur = map;
+        BI.each(values, function (i, value) {
+            if (i > 0 && BI.isPlainObject(cur) && BI.isEmpty(cur)) {
+                return;
+            }
+            if (isLast === true && i === values.length - 1) {
+                cur[value] = {};
+                return;
+            }
+            if (cur[value] == null) {
+                cur[value] = {};
+            }
+            cur = cur[value];
+        })
+    },
+
+    _join: function (valueA, valueB) {
+        var self = this;
+        var hashMap = valueA || {};
+        track([], valueB);
+        function track(parent, node) {
+            BI.each(node, function (n, item) {
+                var next = parent.concat([n]);
+                self._joinTree(hashMap, next, BI.isPlainObject(item) && BI.isEmpty(item));
+                track(next, item);
+            })
+        }
+
+        return hashMap;
+    },
+
+    hasChecked: function () {
+        return !BI.isEmpty(this.selected_values) || BI.SyncTree.superclass.hasChecked.apply(this, arguments);
+    },
+
+    getValue: function () {
+        if (!this.nodes) {
+            return {};
+        }
+        var checkedValues = this._getSelectedValues();
+        if (BI.isEmpty(checkedValues)) {
+            return this.selected_values;
+        }
+        if (BI.isEmpty(this.selected_values)) {
+            return checkedValues;
+        }
+        return this._join(checkedValues, this.selected_values);
+    },
+
+    //生成树方法
+    stroke: function (config) {
+        delete this.options.keyword;
+        BI.extend(this.options.paras, config);
+        //取消选中时使用
+        this.selected_values = BI.deepClone(this.options.paras.selected_values) || {};
+        var setting = this._configSetting();
+        this._initTree(setting);
+    }
+});
+
+$.shortcut("bi.sync_tree", BI.SyncTree);/**
+ * guy
+ * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点
+ * @class BI.PartTree
+ * @extends BI.SyncTree
+ */
+BI.PartTree = BI.inherit(BI.SyncTree, {
+    _defaultConfig: function () {
+        return BI.extend(BI.PartTree.superclass._defaultConfig.apply(this, arguments), {})
+    },
+
+    _init: function () {
+        BI.PartTree.superclass._init.apply(this, arguments);
+    },
+
+    _loadMore: function () {
+        var self = this, o = this.options;
+        var op = BI.extend({}, o.paras, {
+            type: BI.TreeView.REQ_TYPE_INIT_DATA,
+            times: ++this.times
+        });
+        this.tip.setLoading();
+        o.itemsCreator(op, function (d) {
+            var hasNext = !!d.hasNext, nodes = d.items || [];
+            o.paras.last_search_value = d.last_search_value;
+            if (self._stop === true) {
+                return;
+            }
+            if (!hasNext) {
+                self.tip.setEnd();
+            } else {
+                self.tip.setLoaded();
+            }
+            if (nodes.length > 0) {
+                self.nodes.addNodes(null, self._dealWidthNodes(nodes));
+            }
+        });
+    },
+
+    _selectTreeNode: function (treeId, treeNode) {
+        var self = this, o = this.options;
+        var parent_values = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode));
+        var name = this._getNodeValue(treeNode)
+//        var values = parent_values.concat([name]);
+        if (treeNode.checked === true) {
+            BI.SyncTree.superclass._selectTreeNode.apply(self, arguments);
+        } else {
+            o.itemsCreator(BI.extend({}, o.paras, {
+                type: BI.TreeView.REQ_TYPE_CALCULATE_SELECT_DATA,
+                selected_values: this.selected_values,
+                not_selected_value: name,
+                parent_values: parent_values
+            }), function (new_values) {
+                if (BI.isEqual(self.selected_values, new_values)) {
+                    var tNode = treeNode;
+                    var pNode = self._getTree(new_values, parent_values);
+                    if (pNode[name]) {
+                        delete pNode[name];
+                    }
+                    while (tNode != null && BI.isEmpty(pNode)) {
+                        parent_values = parent_values.slice(0, parent_values.length - 1);
+                        tNode = tNode.getParentNode();
+                        if (tNode != null) {
+                            pNode = self._getTree(new_values, parent_values);
+                            name = self._getNodeValue(tNode);
+                            delete pNode[name];
+                        }
+                    }
+                }
+                self.selected_values = new_values;
+                BI.SyncTree.superclass._selectTreeNode.apply(self, arguments);
+            });
+        }
+    },
+
+    _getSelectedValues: function () {
+        var self = this;
+        var hashMap = {};
+        var rootNoots = this.nodes.getNodes();
+        track(rootNoots);
+        function track(nodes) {
+            BI.each(nodes, function (i, node) {
+                var checkState = node.getCheckStatus();
+                if (checkState.checked === false) {
+                    return true;
+                }
+                var parentValues = node.parentValues || self._getParentValues(node);
+                //把文字中的html去掉,其实就是把文字颜色去掉
+                var values = parentValues.concat([self._getNodeValue(node)]);
+                self._buildTree(hashMap, values);
+//                if(checkState.checked === true && checkState.half === false && nodes[i].flag === true){
+//                    continue;
+//                }
+                if (BI.isNotEmptyArray(node.children)) {
+                    track(node.children);
+                    return true;
+                }
+                if (checkState.half === true) {
+                    self._getHalfSelectedValues(hashMap, node);
+                }
+            })
+        }
+
+        return hashMap;
+    },
+
+    _initTree: function (setting, keyword) {
+        var self = this, o = this.options;
+        this.times = 1;
+        var tree = this.tree;
+        tree.empty();
+        self.tip.setVisible(false);
+        this.loading();
+        var op = BI.extend({}, o.paras, {
+            type: BI.TreeView.REQ_TYPE_INIT_DATA,
+            times: this.times
+        });
+        var complete = function (d) {
+            if (self._stop === true || keyword != o.paras.keyword) {
+                return;
+            }
+            var hasNext = !!d.hasNext, nodes = d.items || [];
+            o.paras.last_search_value = d.last_search_value;
+            if (nodes.length > 0) {
+                callback(self._dealWidthNodes(nodes));
+            }
+            self.setTipVisible(nodes.length <= 0);
+            self.loaded();
+            if (!hasNext) {
+                self.tip.invisible();
+            } else {
+                self.tip.setLoaded();
+            }
+            self.fireEvent(BI.Events.AFTERINIT);
+        };
+
+        function callback(nodes) {
+            if (self._stop === true) {
+                return;
+            }
+            self.nodes = $.fn.zTree.init(tree.element, setting, nodes);
+        }
+
+        BI.delay(function () {
+            o.itemsCreator(op, complete);
+        }, 100);
+    },
+
+    getValue: function () {
+        var o = this.options;
+        var result = BI.PartTree.superclass.getValue.apply(this, arguments);
+        o.itemsCreator({
+            type: BI.TreeView.REQ_TYPE_ADJUST_DATA,
+            selected_values: result
+        }, function (res) {
+            result = res;
+        });
+        return result;
+    },
+
+    //生成树方法
+    stroke: function (config) {
+        var o = this.options;
+        delete o.paras.keyword;
+        BI.extend(o.paras, config);
+        delete o.paras.last_search_value;
+        //取消选中时使用
+        this.selected_values = BI.deepClone(o.paras.selected_values) || {};
+        //delete this.options.paras.selected_values;
+        var setting = this._configSetting();
+        this._initTree(setting, o.paras.keyword);
+    }
+});
+
+$.shortcut("bi.part_tree", BI.PartTree);/**
+ *
+ * 自定义树
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.CustomTree
+ * @extends BI.Single
+ */
+BI.CustomTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.CustomTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-custom-tree",
+            expander: {
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            },
+
+            items: [],
+            itemsCreator: BI.emptyFn,
+
+            el: {
+                type: "bi.button_tree",
+                chooseType: 0,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        })
+    },
+
+    _init: function () {
+        BI.CustomTree.superclass._init.apply(this, arguments);
+        this.initTree(this.options.items);
+    },
+
+    setEnable: function (v) {
+        BI.CustomTree.superclass.setEnable.apply(this, arguments);
+        this.tree.setEnable(v)
+    },
+
+    _formatItems: function (nodes) {
+        var self = this, o = this.options;
+        nodes = BI.Tree.transformToTreeFormat(nodes);
+
+        var items = [];
+        BI.each(nodes, function (i, node) {
+            if (BI.isNotEmptyArray(node.children) || node.isParent === true) {
+                var item = BI.extend({
+                    type: "bi.expander",
+                    el: {},
+                    popup: {type: "bi.custom_tree"}
+                }, BI.deepClone(o.expander), {
+                    id: node.id,
+                    pId: node.pId,
+                    value: node.value
+                });
+                var el = BI.stripEL(node);
+                if (!BI.isWidget(el)) {
+                    el = BI.clone(el);
+                    delete el.children;
+                    BI.extend(item.el, el);
+                } else {
+                    item.el = el;
+                }
+                item.popup.expander = BI.deepClone(o.expander);
+                item.items = item.popup.items = node.children;
+                item.itemsCreator = item.popup.itemsCreator = function (op) {
+                    if (BI.isNotNull(op.node)) {//从子节点传过来的itemsCreator直接向上传递
+                        return o.itemsCreator.apply(self, arguments);
+                    }
+                    var args = Array.prototype.slice.call(arguments, 0);
+                    args[0].node = node;
+                    return o.itemsCreator.apply(self, args);
+                };
+                BI.isNull(item.popup.el) && (item.popup.el = BI.deepClone(o.el));
+                items.push(item);
+            } else {
+                items.push(node);
+            }
+        });
+        return items;
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.tree = BI.createWidget(o.el, {
+            element: this,
+            items: this._formatItems(nodes),
+            itemsCreator: function (op, callback) {
+                o.itemsCreator.apply(this, [op, function (items) {
+                    var args = Array.prototype.slice.call(arguments, 0);
+                    args[0] = self._formatItems(items);
+                    callback.apply(null, args);
+                }]);
+            }
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.CustomTree.EVENT_CHANGE, val, obj);
+            }
+        })
+    },
+
+    //生成树方法
+    stroke: function (nodes) {
+        this.populate.apply(this, arguments);
+    },
+
+    populate: function (nodes) {
+        var args = Array.prototype.slice.call(arguments, 0);
+        if (arguments.length > 0) {
+            args[0] = this._formatItems(nodes);
+        }
+        this.tree.populate.apply(this.tree, args);
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree && this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree ? this.tree.getValue() : [];
+    },
+
+    getAllButtons: function () {
+        return this.tree ? this.tree.getAllButtons() : [];
+    },
+
+    getAllLeaves: function () {
+        return this.tree ? this.tree.getAllLeaves() : [];
+    },
+
+    getNodeById: function (id) {
+        return this.tree && this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree && this.tree.getNodeByValue(id);
+    },
+
+    empty: function () {
+        this.tree.empty();
+    }
+});
+BI.CustomTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.custom_tree", BI.CustomTree);
\ No newline at end of file
diff --git a/dist/case.js b/dist/case.js
new file mode 100644
index 000000000..a9e4f2c7a
--- /dev/null
+++ b/dist/case.js
@@ -0,0 +1,8025 @@
+/**
+ * 可以改变图标的button
+ *
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconChangeButton
+ * @extends BI.Single
+ */
+BI.IconChangeButton = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.IconChangeButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-icon-change-button",
+            iconClass: "",
+            iconWidth: null,
+            iconHeight: null,
+
+            stopEvent: false,
+            stopPropagation: false,
+            selected: false,
+            once: false, //点击一次选中有效,再点无效
+            forceSelected: false, //点击即选中, 选中了就不会被取消
+            forceNotSelected: false, //无论怎么点击都不会被选中
+            disableSelected: false, //使能选中
+
+            shadow: false,
+            isShadowShowingOnSelected: false,  //选中状态下是否显示阴影
+            trigger: null,
+            handler: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.IconChangeButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button = BI.createWidget({
+            type: "bi.icon_button",
+            element: this,
+            cls: o.iconClass,
+            height: o.height,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight,
+
+            stopEvent: o.stopEvent,
+            stopPropagation: o.stopPropagation,
+            selected: o.selected,
+            once: o.once,
+            forceSelected: o.forceSelected,
+            forceNotSelected: o.forceNotSelected,
+            disableSelected: o.disableSelected,
+
+            shadow: o.shadow,
+            isShadowShowingOnSelected: o.isShadowShowingOnSelected,
+            trigger: o.trigger,
+            handler: o.handler
+        });
+
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.IconChangeButton.EVENT_CHANGE, arguments);
+        });
+    },
+
+    isSelected: function () {
+        return this.button.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.button.setSelected(b);
+    },
+
+    setIcon: function (cls) {
+        var o = this.options;
+        if (o.iconClass !== cls) {
+            this.element.removeClass(o.iconClass).addClass(cls);
+            o.iconClass = cls;
+        }
+    },
+
+    setEnable: function (b) {
+        BI.IconChangeButton.superclass.setEnable.apply(this, arguments);
+        this.button.setEnable(b);
+    }
+});
+BI.IconChangeButton.EVENT_CHANGE = "IconChangeButton.EVENT_CHANGE";
+$.shortcut("bi.icon_change_button", BI.IconChangeButton);/**
+ * guy
+ * @extends BI.Single
+ * @type {*|void|Object}
+ */
+BI.HalfIconButton = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        var conf = BI.HalfIconButton.superclass._defaultConfig.apply(this,arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-half-icon-button check-half-select-icon",
+            height: 16,
+            width: 16,
+            iconWidth: 16,
+            iconHeight: 16,
+            selected: false
+        })
+    },
+
+    _init : function() {
+        BI.HalfIconButton.superclass._init.apply(this, arguments);
+    },
+
+    doClick: function(){
+        BI.HalfIconButton.superclass.doClick.apply(this, arguments);
+        if(this.isValid()){
+            this.fireEvent(BI.HalfIconButton.EVENT_CHANGE);
+        }
+    }
+});
+BI.HalfIconButton.EVENT_CHANGE = "HalfIconButton.EVENT_CHANGE";
+
+$.shortcut("bi.half_icon_button", BI.HalfIconButton);/**
+ *  统一的trigger图标按钮
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.TriggerIconButton
+ * @extends BI.IconButton
+ */
+BI.TriggerIconButton = BI.inherit(BI.IconButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.TriggerIconButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-trigger-icon-button",
+            extraCls: "pull-down-font"
+        });
+    },
+
+    _init: function () {
+        BI.TriggerIconButton.superclass._init.apply(this, arguments);
+    },
+
+    doClick: function () {
+        BI.TriggerIconButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.TriggerIconButton.EVENT_CHANGE, this);
+        }
+    }
+});
+BI.TriggerIconButton.EVENT_CHANGE = "TriggerIconButton.EVENT_CHANGE";
+$.shortcut("bi.trigger_icon_button", BI.TriggerIconButton);/**
+ * guy
+ * 复选框item
+ * @type {*|void|Object}
+ */
+BI.MultiSelectItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function() {
+        return BI.extend(BI.MultiSelectItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multi-select-item",
+            height: 25,
+            logic: {
+                dynamic: false
+            }
+        })
+    },
+    _init : function() {
+        BI.MultiSelectItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            rgap: o.rgap,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function(type){
+            if(type ===  BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", {
+                type: "bi.center_adapt",
+                items: [this.checkbox],
+                width: 36
+            } ,this.text)
+        }))));
+    },
+
+    doRedMark: function(){
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function(){
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function(){
+        BI.MultiSelectItem.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setSelected: function(v){
+        BI.MultiSelectItem.superclass.setSelected.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multi_select_item", BI.MultiSelectItem);/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.SingleSelectIconTextItem
+ * @extends BI.BasicButton
+ */
+BI.SingleSelectIconTextItem = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleSelectIconTextItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-single-select-icon-text-item bi-list-item-active",
+            iconClass: "",
+            hgap: 10,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SingleSelectIconTextItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.icon_text_item",
+            element: this,
+            cls: o.iconClass,
+            once: o.once,
+            selected: o.selected,
+            height: o.height,
+            iconHeight: o.iconHeight,
+            iconWidth: o.iconWidth,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py
+        });
+        this.text.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    isSelected: function () {
+        return this.text.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.text.setSelected(b);
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SingleSelectIconTextItem.superclass.doClick.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.single_select_icon_text_item", BI.SingleSelectIconTextItem);/**
+ * guy
+ * 复选框item
+ * @type {*|void|Object}
+ */
+BI.SingleSelectItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleSelectItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-single-select-item bi-list-item-active",
+            hgap: 10,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SingleSelectItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py
+        });
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SingleSelectItem.superclass.doClick.apply(this, arguments);
+    },
+
+    setSelected: function (v) {
+        BI.SingleSelectItem.superclass.setSelected.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.single_select_item", BI.SingleSelectItem);/**
+ * guy
+ * 单选框item
+ * @type {*|void|Object}
+ */
+BI.SingleSelectRadioItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleSelectRadioItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-single-select-radio-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            hgap: 10,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SingleSelectRadioItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio"
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(!self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", {
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: 36
+            }, this.text)
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SingleSelectRadioItem.superclass.doClick.apply(this, arguments);
+        this.radio.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.SingleSelectRadioItem.superclass.setSelected.apply(this, arguments);
+        this.radio.setSelected(v);
+
+    }
+});
+
+$.shortcut("bi.single_select_radio_item", BI.SingleSelectRadioItem);/**
+ * Created by roy on 15/10/16.
+ */
+BI.ArrowNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.ArrowNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-arrow-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        });
+    },
+    _init: function () {
+        var self = this, o = this.options;
+        BI.ArrowNode.superclass._init.apply(this, arguments);
+        this.checkbox = BI.createWidget({
+            type: "bi.arrow_tree_group_node_checkbox",
+            iconWidth: 13,
+            iconHeight: 13
+        });
+
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.ArrowNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+    setValue: function (v) {
+        this.text.setValue(v);
+    },
+
+    setOpened: function (v) {
+        BI.ArrowNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    }
+});
+
+$.shortcut("bi.arrow_group_node", BI.ArrowNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.FirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.FirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.FirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-first-plus-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.FirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.first_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.FirstPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.FirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.first_plus_group_node", BI.FirstPlusGroupNode);/**
+ * Created by User on 2016/3/31.
+ */
+/**
+ * > + icon + 文本
+ * @class BI.IconArrowNode
+ * @extends BI.NodeButton
+ */
+BI.IconArrowNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.IconArrowNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-icon-arrow-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25,
+            iconHeight: 13,
+            iconWidth: 13,
+            iconCls: ""
+        })
+    },
+    _init: function () {
+        BI.IconArrowNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox",
+            width: 23,
+            stopPropagation: true
+        });
+
+        var icon = BI.createWidget({
+            type: "bi.center_adapt",
+            cls: o.iconCls,
+            width: 23,
+            items: [{
+                type: "bi.icon",
+                height: o.iconHeight,
+                width: o.iconWidth
+            }]
+        });
+
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, {
+            width: 23,
+            el: icon
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.IconArrowNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.IconArrowNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.icon_arrow_node", BI.IconArrowNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.LastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.LastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.LastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-last-plus-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.LastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.last_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if(type ===  BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.LastPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.LastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.last_plus_group_node", BI.LastPlusGroupNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.MidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-mid-plus-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.mid_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.MidPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.mid_plus_group_node", BI.MidPlusGroupNode);BI.MultiLayerIconArrowNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerIconArrowNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-icon-arrow-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25,
+            iconHeight: 13,
+            iconWidth: 13,
+            iconCls: ""
+        })
+    },
+    _init: function () {
+        BI.MultiLayerIconArrowNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.icon_arrow_node",
+            iconCls: o.iconCls,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            iconHeight: o.iconHeight,
+            iconWidth: o.iconWidth,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerIconArrowNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerIconArrowNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_icon_arrow_node", BI.MultiLayerIconArrowNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.PlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.PlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.PlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-plus-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.PlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.PlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.PlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (this.checkbox) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.plus_group_node", BI.PlusGroupNode);/**
+ * 三角号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.TriangleGroupNode
+ * @extends BI.NodeButton
+ */
+BI.TriangleGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.TriangleGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-triangle-group-node bi-list-item",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.TriangleGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            iconWidth: 13,
+            iconHeight: 13,
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py,
+            keyword: o.keyword
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.TriangleGroupNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.TriangleGroupNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setText: function(text){
+        BI.TriangleGroupNode.superclass.setText.apply(this, arguments);
+        this.text.setText(text);
+    }
+});
+
+$.shortcut("bi.triangle_group_node", BI.TriangleGroupNode);/**
+ * guy
+ * 复选框item
+ * @type {*|void|Object}
+ */
+BI.FirstTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FirstTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-first-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            layer: 0,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.FirstTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : {
+            width: 13,
+            el: {
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            }
+        }), {
+            width: 25,
+            el: {
+                type: "bi.layout",
+                cls: "mid-line-conn-background",
+                width: 25,
+                height: o.height
+            }
+        }, {
+            el: this.text
+        });
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.FirstTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.FirstTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    }
+});
+
+$.shortcut("bi.first_tree_leaf_item", BI.FirstTreeLeafItem);BI.IconTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-icon-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            height: 25,
+            iconWidth: 16,
+            iconHeight: 16,
+            iconCls: ""
+        })
+    },
+
+    _init: function () {
+        BI.IconTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        var icon = BI.createWidget({
+            type: "bi.center_adapt",
+            width: 23,
+            cls: o.iconCls,
+            items: [{
+                type: "bi.icon",
+                width: o.iconWidth,
+                height: o.iconHeight
+            }]
+        });
+
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 23,
+            el: icon
+        }, {
+            el: this.text
+        });
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.IconTreeLeafItem.superclass.doClick.apply(this, arguments);
+    },
+
+    setSelected: function (v) {
+        BI.IconTreeLeafItem.superclass.setSelected.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.icon_tree_leaf_item", BI.IconTreeLeafItem);/**
+ * guy
+ * 复选框item
+ * @type {*|void|Object}
+ */
+BI.LastTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LastTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-last-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            layer: 0,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.LastTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : {
+            width: 13,
+            el: {
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            }
+        }), {
+            width: 25,
+            el: {
+                type: "bi.layout",
+                cls: "mid-line-conn-background",
+                width: 25,
+                height: o.height
+            }
+        }, {
+            el: this.text
+        });
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.LastTreeLeafItem.superclass.doClick.apply(this, arguments);
+        //    this.checkbox.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.LastTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        //    this.checkbox.setSelected(v);
+    }
+});
+
+$.shortcut("bi.last_tree_leaf_item", BI.LastTreeLeafItem);/**
+ * guy
+ * 复选框item
+ * @type {*|void|Object}
+ */
+BI.MidTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MidTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-mid-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            layer: 0,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MidTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : {
+            width: 13,
+            el: {
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            }
+        }), {
+            width: 25,
+            el: {
+                type: "bi.layout",
+                cls: "mid-line-conn-background",
+                width: 25,
+                height: o.height
+            }
+        }, {
+            el: this.text
+        });
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MidTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MidTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    }
+});
+
+$.shortcut("bi.mid_tree_leaf_item", BI.MidTreeLeafItem);/**
+ * @class BI.MultiLayerIconTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerIconTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerIconTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-icon-tree-leaf-item bi-list-item-active",
+            layer: 0,
+            height: 25,
+            iconCls: "",
+            iconHeight: 14,
+            iconWidth: 12
+        })
+    },
+    _init: function () {
+        BI.MultiLayerIconTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.icon_tree_leaf_item",
+            iconCls: o.iconCls,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            isFront: true,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        });
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerIconTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerIconTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    },
+
+    getValue: function(){
+        return this.options.value;
+    }
+});
+
+$.shortcut("bi.multilayer_icon_tree_leaf_item", BI.MultiLayerIconTreeLeafItem);/**
+ * 树叶子节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.TreeTextLeafItem
+ * @extends BI.BasicButton
+ */
+BI.TreeTextLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function() {
+        return BI.extend(BI.TreeTextLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-tree-text-leaf-item bi-list-item-active",
+            id: "",
+            pId: "",
+            height: 25,
+            hgap: 0,
+            lgap: 0,
+            rgap: 0
+        })
+    },
+    _init : function() {
+        BI.TreeTextLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            lgap: o.lgap,
+            rgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.text
+            }]
+        })
+    },
+
+    doRedMark: function(){
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function(){
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function(){
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function(){
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    getId: function(){
+        return this.options.id;
+    },
+
+    getPId: function(){
+        return this.options.pId;
+    }
+});
+
+$.shortcut("bi.tree_text_leaf_item", BI.TreeTextLeafItem);/**
+ * Created by GUY on 2015/8/28.
+ * @class BI.Calendar
+ * @extends BI.Widget
+ */
+BI.Calendar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.Calendar.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-calendar",
+            logic: {
+                dynamic: false
+            },
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            year: 2015,
+            month: 7,  //7表示八月
+            day: 25
+        })
+    },
+
+    _dateCreator: function (Y, M, D) {
+        var self = this, o = this.options, log = {}, De = new Date();
+        var mins = o.min.match(/\d+/g);
+        var maxs = o.max.match(/\d+/g);
+        Y < (mins[0] | 0) && (Y = (mins[0] | 0));
+        Y > (maxs[0] | 0) && (Y = (maxs[0] | 0));
+
+        De.setFullYear(Y, M, D);
+        log.ymd = [De.getFullYear(), De.getMonth(), De.getDate()];
+
+        Date._MD[1] = Date.isLeap(log.ymd[0]) ? 29 : 28;
+
+        De.setFullYear(log.ymd[0], log.ymd[1], 1);
+        log.FDay = De.getDay();
+
+        log.PDay = Date._MD[M === 0 ? 11 : M - 1] - log.FDay + 1;
+        log.NDay = 1;
+
+        var items = [];
+        BI.each(BI.range(42), function (i) {
+            var td = {}, YY = log.ymd[0], MM = log.ymd[1] + 1, DD;
+            if (i < log.FDay) {
+                td.lastMonth = true;
+                DD = i + log.PDay;
+                MM === 1 && (YY -= 1);
+                MM = MM === 1 ? 12 : MM - 1;
+            } else if (i >= log.FDay && i < log.FDay + Date._MD[log.ymd[1]]) {
+                DD = i - log.FDay + 1;
+                if (i - log.FDay + 1 === log.ymd[2]) {
+                    td.currentDay = true;
+                }
+            } else {
+                td.nextMonth = true;
+                DD = log.NDay++;
+                MM === 12 && (YY += 1);
+                MM = MM === 12 ? 1 : MM + 1;
+            }
+            if (Date.checkVoid(YY, MM, DD, mins, maxs)[0]) {
+                td.disabled = true;
+            }
+            td.text = DD;
+            items.push(td);
+        })
+        return items;
+    },
+
+    _init: function () {
+        BI.Calendar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var items = BI.map(Date._SDN.slice(0, 7), function (i, value) {
+            return {
+                type: "bi.label",
+                height: 25,
+                text: value
+            }
+        })
+        var title = BI.createWidget({
+            type: "bi.button_group",
+            height: 25,
+            items: items
+        })
+        var days = this._dateCreator(o.year, o.month, o.day);
+        items = [];
+        items.push(days.slice(0, 7));
+        items.push(days.slice(7, 14));
+        items.push(days.slice(14, 21));
+        items.push(days.slice(21, 28));
+        items.push(days.slice(28, 35));
+        items.push(days.slice(35, 42));
+
+        items = BI.map(items, function (i, item) {
+            return BI.map(item, function (j, td) {
+                return BI.extend(td, {
+                    type: "bi.text_item",
+                    cls: "bi-list-item-active",
+                    textAlign: "center",
+                    whiteSpace: "normal",
+                    once: false,
+                    forceSelected: true,
+                    height: 25,
+                    value: o.year + "-" + o.month + "-" + td.text,
+                    disabled: td.lastMonth || td.nextMonth || td.disabled
+                    //selected: td.currentDay
+                });
+            });
+        });
+
+        this.days = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(items, {}),
+            layouts: [BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, {
+                columns: 7,
+                rows: 6,
+                columnSize: [1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7],
+                rowSize: 25
+            }))]
+        });
+        this.days.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        })
+        BI.createWidget(BI.extend({
+            element: this
+
+        }, BI.LogicFactory.createLogic("vertical", BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("top", title, this.days)
+        }))));
+    },
+
+    isFrontDate: function () {
+        var o = this.options, c = this._const;
+        var Y = o.year, M = o.month, De = new Date(), day = De.getDay();
+        Y = Y | 0;
+        De.setFullYear(Y, M, 1);
+        var newDate = De.getOffsetDate(-1 * (day + 1));
+        return !!Date.checkVoid(newDate.getFullYear(), newDate.getMonth(), newDate.getDate(), o.min, o.max)[0];
+    },
+
+    isFinalDate: function () {
+        var o = this.options, c = this._const;
+        var Y = o.year, M = o.month, De = new Date(), day = De.getDay();
+        Y = Y | 0;
+        De.setFullYear(Y, M, 1);
+        var newDate = De.getOffsetDate(42 - day);
+        return !!Date.checkVoid(newDate.getFullYear(), newDate.getMonth(), newDate.getDate(), o.min, o.max)[0];
+    },
+
+    setValue: function (ob) {
+        this.days.setValue([ob.year + "-" + ob.month + "-" + ob.day]);
+    },
+
+    getValue: function () {
+        var date = this.days.getValue()[0].match(/\d+/g);
+        return {
+            year: date[0] | 0,
+            month: date[1] | 0,
+            day: date[2] | 0
+        }
+    }
+});
+
+BI.extend(BI.Calendar, {
+    getPageByDateJSON: function (json) {
+        var year = new Date().getFullYear();
+        var month = new Date().getMonth();
+        var page = (json.year - year) * 12;
+        page += json.month - month;
+        return page;
+    }
+});
+
+$.shortcut("bi.calendar", BI.Calendar);/**
+ * Created by GUY on 2015/8/28.
+ * @class BI.YearCalendar
+ * @extends BI.Widget
+ */
+BI.YearCalendar = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        var conf = BI.YearCalendar.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-year-calendar",
+            logic: {
+                dynamic: false
+            },
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            year: null
+        })
+    },
+
+    _yearCreator: function (Y) {
+        var o = this.options;
+        Y = Y | 0;
+        var start = BI.YearCalendar.getStartYear(Y);
+        var items = [];
+        BI.each(BI.range(BI.YearCalendar.INTERVAL), function (i) {
+            var td = {};
+            if (Date.checkVoid(start + i, 1, 1, o.min, o.max)[0]) {
+                td.disabled = true;
+            }
+            td.text = start + i;
+            items.push(td);
+        });
+        return items;
+    },
+
+    _init: function () {
+        BI.YearCalendar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.currentYear = new Date().getFullYear();
+        var years = this._yearCreator(o.year || this.currentYear);
+
+        //纵向排列年
+        var len = years.length, tyears = BI.makeArray(len, "");
+        var map = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11];
+        BI.each(years, function (i, y) {
+            tyears[i] = years[map[i]];
+        });
+        var items = [];
+        items.push(tyears.slice(0, 2));
+        items.push(tyears.slice(2, 4));
+        items.push(tyears.slice(4, 6));
+        items.push(tyears.slice(6, 8));
+        items.push(tyears.slice(8, 10));
+        items.push(tyears.slice(10, 12));
+
+        items = BI.map(items, function (i, item) {
+            return BI.map(item, function (j, td) {
+                return BI.extend(td, {
+                    type: "bi.text_item",
+                    cls: "bi-list-item-active",
+                    textAlign: "center",
+                    whiteSpace: "normal",
+                    once: false,
+                    forceSelected: true,
+                    height: 23,
+                    width: 38,
+                    value: td.text,
+                    disabled: td.disabled
+                });
+            });
+        });
+
+        this.years = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(items, {}),
+            layouts: [BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, {
+                columns: 2,
+                rows: 6,
+                columnSize: [1 / 2, 1 / 2],
+                rowSize: 25
+            })), {
+                type: "bi.center_adapt",
+                vgap: 1
+            }]
+        });
+        this.years.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget(BI.extend({
+            element: this
+
+        }, BI.LogicFactory.createLogic("vertical", BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("top", this.years)
+        }))));
+    },
+
+    isFrontYear: function () {
+        var o = this.options;
+        var Y = o.year;
+        Y = Y | 0;
+        return !!Date.checkVoid(BI.YearCalendar.getStartYear(Y) - 1, 1, 1, o.min, o.max)[0];
+    },
+
+    isFinalYear: function () {
+        var o = this.options, c = this._const;
+        var Y = o.year;
+        Y = Y | 0;
+        return !!Date.checkVoid(BI.YearCalendar.getEndYear(Y) + 1, 1, 1, o.min, o.max)[0];
+    },
+
+    setValue: function (val) {
+        this.years.setValue([val]);
+    },
+
+    getValue: function () {
+        return this.years.getValue()[0];
+    }
+});
+//类方法
+BI.extend(BI.YearCalendar, {
+    INTERVAL: 12,
+
+    //获取显示的第一年
+    getStartYear: function (year) {
+        var cur = new Date().getFullYear();
+        return year - ((year - cur + 3) % BI.YearCalendar.INTERVAL + 12) % BI.YearCalendar.INTERVAL;
+    },
+
+    getEndYear: function (year) {
+        return BI.YearCalendar.getStartYear(year) + BI.YearCalendar.INTERVAL;
+    },
+
+    getPageByYear: function (year) {
+        var cur = new Date().getFullYear();
+        year = BI.YearCalendar.getStartYear(year);
+        return (year - cur + 3) / BI.YearCalendar.INTERVAL;
+    }
+});
+
+$.shortcut("bi.year_calendar", BI.YearCalendar);/**
+ * 绘制一些较复杂的canvas
+ *
+ * Created by GUY on 2015/11/24.
+ * @class BI.ComplexCanvas
+ * @extends BI.Widget
+ */
+BI.ComplexCanvas = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ComplexCanvas.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-complex-canvas"
+        })
+    },
+
+
+    _init: function () {
+        BI.ComplexCanvas.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.canvas = BI.createWidget({
+            type: "bi.canvas",
+            element: this,
+            width: o.width,
+            height: o.height
+        });
+    },
+
+    //绘制树枝节点
+    branch: function (x0, y0, x1, y1, x2, y2) {
+        var self = this, args = [].slice.call(arguments);
+        if (args.length <= 5) {
+            return this.canvas.line.apply(this.canvas, arguments);
+        }
+        var options;
+        if (BI.isOdd(args.length)) {
+            options = BI.last(args);
+            args = BI.initial(args);
+        }
+        args = [].slice.call(args, 2);
+        var odd = BI.filter(args, function (i) {
+            return i % 2 === 0;
+        });
+        var even = BI.filter(args, function (i) {
+            return i % 2 !== 0;
+        });
+        options || (options = {});
+        var offset = options.offset || 20;
+        if ((y0 > y1 && y0 > y2) || (y0 < y1 && y0 < y2)) {
+            if (y0 > y1 && y0 > y2) {
+                var y = Math.max.apply(this, even) + offset;
+            } else {
+                var y = Math.min.apply(this, even) - offset;
+            }
+            var minx = Math.min.apply(this, odd);
+            var minix = BI.indexOf(odd, minx);
+            var maxx = Math.max.apply(this, odd);
+            var maxix = BI.indexOf(odd, maxx);
+            this.canvas.line(minx, even[minix], minx, y, maxx, y, maxx, even[maxix], options);
+            BI.each(odd, function (i, dot) {
+                if (i !== maxix && i !== minix) {
+                    self.canvas.line(dot, even[i], dot, y, options);
+                }
+            });
+            this.canvas.line(x0, y, x0, y0, options);
+            return;
+        }
+        if ((x0 > x1 && x0 > x2) || (x0 < x1 && x0 < x2)) {
+            if (x0 > x1 && x0 > x2) {
+                var x = Math.max.apply(this, odd) + offset;
+            } else {
+                var x = Math.min.apply(this, odd) - offset;
+            }
+            var miny = Math.min.apply(this, even);
+            var miniy = BI.indexOf(even, miny);
+            var maxy = Math.max.apply(this, even);
+            var maxiy = BI.indexOf(even, maxy);
+            this.canvas.line(odd[miniy], miny, x, miny, x, maxy, odd[maxiy], maxy, options);
+            BI.each(even, function (i, dot) {
+                if (i !== miniy && i !== maxiy) {
+                    self.canvas.line(odd[i], dot, x, dot, options);
+                }
+            });
+            this.canvas.line(x, y0, x0, y0, options);
+            return;
+        }
+    },
+
+    stroke: function (callback) {
+        this.canvas.stroke(callback);
+    }
+});
+
+$.shortcut("bi.complex_canvas", BI.ComplexCanvas);/**
+ * Created by roy on 15/10/16.
+ * 上箭头与下箭头切换的树节点
+ */
+BI.ArrowTreeGroupNodeCheckbox=BI.inherit(BI.IconButton,{
+    _defaultConfig:function(){
+        return BI.extend(BI.ArrowTreeGroupNodeCheckbox.superclass._defaultConfig.apply(this,arguments),{
+            extraCls:"bi-arrow-tree-group-node",
+            iconWidth: 13,
+            iconHeight: 13
+        });
+    },
+    _init:function(){
+        BI.ArrowTreeGroupNodeCheckbox.superclass._init.apply(this,arguments);
+    },
+    setSelected: function(v){
+        BI.ArrowTreeGroupNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v) {
+            this.element.removeClass("column-next-page-h-font").addClass("column-pre-page-h-font");
+        } else {
+            this.element.removeClass("column-pre-page-h-font").addClass("column-next-page-h-font");
+        }
+    }
+});
+$.shortcut("bi.arrow_tree_group_node_checkbox",BI.ArrowTreeGroupNodeCheckbox);/**
+ * 十字型的树节点
+ * @class BI.CheckingMarkNode
+ * @extends BI.IconButton
+ */
+BI.CheckingMarkNode = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.CheckingMarkNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "check-mark-font",
+            iconWidth: 13,
+            iconHeight: 13
+        });
+    },
+    _init:function() {
+        BI.CheckingMarkNode.superclass._init.apply(this, arguments);
+        this.setSelected(this.options.selected);
+
+    },
+    setSelected: function(v){
+        BI.CheckingMarkNode.superclass.setSelected.apply(this, arguments);
+        if(v===true) {
+            this.element.addClass("check-mark-font");
+        } else {
+            this.element.removeClass("check-mark-font");
+        }
+    }
+});
+$.shortcut("bi.checking_mark_node", BI.CheckingMarkNode);/**
+ * 十字型的树节点
+ * @class BI.FirstTreeNodeCheckbox
+ * @extends BI.IconButton
+ */
+BI.FirstTreeNodeCheckbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.FirstTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "tree-collapse-icon-type2",
+            iconWidth: 25,
+            iconHeight: 25
+        });
+    },
+    _init:function() {
+        BI.FirstTreeNodeCheckbox.superclass._init.apply(this, arguments);
+
+    },
+    setSelected: function(v){
+        BI.FirstTreeNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v===true) {
+            this.element.addClass("tree-expand-icon-type2");
+        } else {
+            this.element.removeClass("tree-expand-icon-type2");
+        }
+    }
+});
+$.shortcut("bi.first_tree_node_checkbox", BI.FirstTreeNodeCheckbox);/**
+ * 十字型的树节点
+ * @class BI.LastTreeNodeCheckbox
+ * @extends BI.IconButton
+ */
+BI.LastTreeNodeCheckbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.LastTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "tree-collapse-icon-type4",
+            iconWidth: 25,
+            iconHeight: 25
+        });
+    },
+    _init:function() {
+        BI.LastTreeNodeCheckbox.superclass._init.apply(this, arguments);
+
+    },
+    setSelected: function(v){
+        BI.LastTreeNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v===true) {
+            this.element.addClass("tree-expand-icon-type3");
+        } else {
+            this.element.removeClass("tree-expand-icon-type3");
+        }
+    }
+});
+$.shortcut("bi.last_tree_node_checkbox", BI.LastTreeNodeCheckbox);/**
+ * 十字型的树节点
+ * @class BI.MidTreeNodeCheckbox
+ * @extends BI.IconButton
+ */
+BI.MidTreeNodeCheckbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.MidTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "tree-collapse-icon-type3",
+            iconWidth: 25,
+            iconHeight: 25
+        });
+    },
+    _init:function() {
+        BI.MidTreeNodeCheckbox.superclass._init.apply(this, arguments);
+
+    },
+    setSelected: function(v){
+        BI.MidTreeNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v===true) {
+            this.element.addClass("tree-expand-icon-type3");
+        } else {
+            this.element.removeClass("tree-expand-icon-type3");
+        }
+    }
+});
+$.shortcut("bi.mid_tree_node_checkbox", BI.MidTreeNodeCheckbox);/**
+ * 三角形的树节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.TreeGroupNodeCheckbox
+ * @extends BI.IconButton
+ */
+BI.TreeGroupNodeCheckbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.TreeGroupNodeCheckbox.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "tree-node-triangle-collapse-font",
+            iconWidth: 13,
+            iconHeight: 13
+        });
+    },
+    _init:function() {
+        BI.TreeGroupNodeCheckbox.superclass._init.apply(this, arguments);
+
+    },
+    setSelected: function(v){
+        BI.TreeGroupNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v) {
+            this.element.removeClass("tree-node-triangle-collapse-font").addClass("tree-node-triangle-expand-font");
+        } else {
+            this.element.removeClass("tree-node-triangle-expand-font").addClass("tree-node-triangle-collapse-font");
+        }
+    }
+});
+$.shortcut("bi.tree_group_node_checkbox", BI.TreeGroupNodeCheckbox);/**
+ * 十字型的树节点
+ * @class BI.TreeNodeCheckbox
+ * @extends BI.IconButton
+ */
+BI.TreeNodeCheckbox = BI.inherit(BI.IconButton, {
+    _defaultConfig: function() {
+        return BI.extend( BI.TreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "tree-collapse-icon-type1",
+            iconWidth: 25,
+            iconHeight: 25
+        });
+    },
+    _init:function() {
+        BI.TreeNodeCheckbox.superclass._init.apply(this, arguments);
+
+    },
+    setSelected: function(v){
+        BI.TreeNodeCheckbox.superclass.setSelected.apply(this, arguments);
+        if(v) {
+            this.element.addClass("tree-expand-icon-type1");
+        } else {
+            this.element.removeClass("tree-expand-icon-type1");
+        }
+    }
+});
+$.shortcut("bi.tree_node_checkbox", BI.TreeNodeCheckbox);/**
+ * 简单选色控件按钮
+ *
+ * Created by GUY on 2015/11/16.
+ * @class BI.ColorPickerButton
+ * @extends BI.BasicButton
+ */
+BI.ColorPickerButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.ColorPickerButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-color-picker-button"
+        })
+    },
+
+    _init: function () {
+        BI.ColorPickerButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (o.value) {
+            this.element.css("background-color", o.value);
+            var name = this.getName();
+            this.element.hover(function () {
+                self._createMask();
+                if (self.isEnabled()) {
+                    BI.Maskers.show(name);
+                }
+            }, function () {
+                if (!self.isSelected()) {
+                    BI.Maskers.hide(name);
+                }
+            });
+        }
+    },
+
+    _createMask: function () {
+        var o = this.options, name = this.getName();
+        if (this.isEnabled() && !BI.Maskers.has(name)) {
+            var w = BI.Maskers.make(name, this, {
+                offset: {
+                    left: -1,
+                    top: -1,
+                    right: -1,
+                    bottom: -1
+                }
+            });
+            w.element.addClass("color-picker-button-mask").css("background-color", o.value);
+        }
+    },
+
+    setSelected: function (b) {
+        BI.ColorPickerButton.superclass.setSelected.apply(this, arguments);
+        if (!!b) {
+            this._createMask();
+        }
+        BI.Maskers[!!b ? "show" : "hide"](this.getName());
+    }
+});
+BI.ColorPickerButton.EVENT_CHANGE = "ColorPickerButton.EVENT_CHANGE";
+$.shortcut("bi.color_picker_button", BI.ColorPickerButton);/**
+ * 简单选色控件
+ *
+ * Created by GUY on 2015/11/16.
+ * @class BI.ColorPicker
+ * @extends BI.Widget
+ */
+BI.ColorPicker = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorPicker.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-picker",
+            items: null
+        })
+    },
+
+    _items: [
+        [{
+            value: "#ff0000"
+        }, {
+            value: "#ffff02"
+        }, {
+            value: "#00ff00"
+        }, {
+            value: "#00ffff"
+        }, {
+            value: "#0000ff"
+        }, {
+            value: "#ff02ff"
+        }, {
+            value: "#ffffff"
+        }, {
+            value: "#e6e6e6"
+        }, {
+            value: "#cccccc"
+        }, {
+            value: "#b3b3b3"
+        }, {
+            value: "#999999"
+        }, {
+            value: "#808080"
+        }, {
+            value: "#666666"
+        }, {
+            value: "#4d4d4d"
+        }, {
+            value: "#333333"
+        }, {
+            value: "#1a1a1a"
+        }],
+        [{
+            value: "#ea9b5e"
+        }, {
+            value: "#ebb668"
+        }, {
+            value: "#efca69"
+        }, {
+            value: "#faf4a2"
+        }, {
+            value: "#c9da73"
+        }, {
+            value: "#b6d19c"
+        }, {
+            value: "#86be85"
+        }, {
+            value: "#87c5c3"
+        }, {
+            value: "#75bfec"
+        }, {
+            value: "#85a9e0"
+        }, {
+            value: "#8890d3"
+        }, {
+            value: "#a484b9"
+        }, {
+            value: "#b48bbf"
+        }, {
+            value: "#ba8dc6"
+        }, {
+            value: "#e697c8"
+        }, {
+            value: "#e49da0"
+        }],
+        [{
+            value: "#df6a18"
+        }, {
+            value: "#df8d04"
+        }, {
+            value: "#efb500"
+        }, {
+            value: "#faf201"
+        }, {
+            value: "#b2cc23"
+        }, {
+            value: "#7dbd2f"
+        }, {
+            value: "#48a754"
+        }, {
+            value: "#27acaa"
+        }, {
+            value: "#09abe9"
+        }, {
+            value: "#357bcc"
+        }, {
+            value: "#4d67c1"
+        }, {
+            value: "#5b4aa5"
+        }, {
+            value: "#7e52a5"
+        }, {
+            value: "#a057a4"
+        }, {
+            value: "#d1689c"
+        }, {
+            value: "#d66871"
+        }],
+        [{
+            value: "#d12d02"
+        }, {
+            value: "#db6700"
+        }, {
+            value: "#ee9106"
+        }, {
+            value: "#f7ed02"
+        }, {
+            value: "#92b801"
+        }, {
+            value: "#37a600"
+        }, {
+            value: "#289100"
+        }, {
+            value: "#1a9589"
+        }, {
+            value: "#0292e0"
+        }, {
+            value: "#005dbb"
+        }, {
+            value: "#005eb4"
+        }, {
+            value: "#0041a3"
+        }, {
+            value: "#00217f"
+        }, {
+            value: "#811e89"
+        }, {
+            value: "#cd2a7c"
+        }, {
+            value: "#cd324a"
+        }]
+    ],
+
+    _init: function () {
+        BI.ColorPicker.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.colors = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(o.items || this._items, {
+                type: "bi.color_picker_button",
+                once: false
+            }),
+            layouts: [{
+                type: "bi.grid"
+            }]
+        });
+        this.colors.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.ColorPicker.EVENT_CHANGE, arguments);
+        })
+    },
+
+    populate: function(items){
+        var args  =[].slice.call(arguments);
+        args[0] = BI.createItems(items, {
+            type: "bi.color_picker_button",
+            once: false
+        });
+        this.colors.populate.apply(this.colors, args);
+    },
+
+    setValue: function (color) {
+        this.colors.setValue(color);
+    },
+
+    getValue: function () {
+        return this.colors.getValue();
+    }
+});
+BI.ColorPicker.EVENT_CHANGE = "ColorPicker.EVENT_CHANGE";
+$.shortcut("bi.color_picker", BI.ColorPicker);/**
+ * 简单选色控件
+ *
+ * Created by GUY on 2015/11/16.
+ * @class BI.ColorPickerEditor
+ * @extends BI.Widget
+ */
+BI.ColorPickerEditor = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorPickerEditor.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-picker-editor",
+            width: 190,
+            height: 20
+        })
+    },
+
+    _init: function () {
+        BI.ColorPickerEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.colorShow = BI.createWidget({
+            type: "bi.layout",
+            cls: "color-picker-editor-display",
+            height: 20
+        });
+        var RGB = BI.createWidgets(BI.createItems([{text: "R"}, {text: "G"}, {text: "B"}], {
+            type: "bi.label",
+            cls: "color-picker-editor-label",
+            width: 10,
+            height: 20
+        }));
+
+        var checker = function (v) {
+            return BI.isNumeric(v) && (v | 0) >= 0 && (v | 0) <= 255;
+        };
+        var Ws = BI.createWidgets([{}, {}, {}], {
+            type: "bi.small_text_editor",
+            cls: "color-picker-editor-input",
+            validationChecker: checker,
+            errorText: BI.i18nText("BI-Color_Picker_Error_Text"),
+            value: 255,
+            width: 35,
+            height: 20
+        });
+        BI.each(Ws, function (i, w) {
+            w.on(BI.TextEditor.EVENT_CHANGE, function () {
+                if (self.R.isValid() && self.G.isValid() && self.B.isValid()) {
+                    self.colorShow.element.css("background-color", self.getValue());
+                    self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
+                }
+            });
+        });
+        this.R = Ws[0];
+        this.G = Ws[1];
+        this.B = Ws[2];
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.colorShow,
+                width: 'fill'
+            }, {
+                el: RGB[0],
+                lgap: 10,
+                width: 20
+            }, {
+                el: this.R,
+                width: 35
+            }, {
+                el: RGB[1],
+                lgap: 10,
+                width: 20
+            }, {
+                el: this.G,
+                width: 35
+            }, {
+                el: RGB[2],
+                lgap: 10,
+                width: 20
+            }, {
+                el: this.B,
+                width: 35
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        color || (color = "#000000");
+        this.colorShow.element.css("background-color", color);
+        var json = BI.DOM.rgb2json(BI.DOM.hex2rgb(color));
+        this.R.setValue(json.r);
+        this.G.setValue(json.g);
+        this.B.setValue(json.b);
+    },
+
+    getValue: function () {
+        return BI.DOM.rgb2hex(BI.DOM.json2rgb({
+            r: this.R.getValue(),
+            g: this.G.getValue(),
+            b: this.B.getValue()
+        }))
+    }
+});
+BI.ColorPickerEditor.EVENT_CHANGE = "ColorPickerEditor.EVENT_CHANGE";
+$.shortcut("bi.color_picker_editor", BI.ColorPickerEditor);/**
+ * guy
+ * 记录内容的输入框
+ * @class BI.RecordEditor
+ * @extends BI.Single
+ */
+BI.RecordEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function() {
+        var conf = BI.RecordEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf , {
+            baseCls: (conf.baseCls || "") + " bi-record-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init : function() {
+        BI.RecordEditor.superclass._init.apply(this, arguments);
+        this.contents = [];
+        var self = this, o = this.options;
+
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank : o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.textContainer = BI.createWidget({
+            type: "bi.vertical_adapt",
+            hgap: 2,
+            height: o.height
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function(){
+            self._checkInputState();
+            self.fireEvent(BI.RecordEditor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function(){
+            self._checkInputState();
+            self.fireEvent(BI.RecordEditor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function(v){
+            self.fireEvent(BI.RecordEditor.EVENT_KEY_DOWN, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function(){
+            self.setValue(self.getValue());
+            self.editor.isValid() && self.editor.setValue("");
+            self.fireEvent(BI.RecordEditor.EVENT_CONFIRM, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.RecordEditor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function(){
+            self._checkInputState();
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function(){
+            if(!BI.isEmpty(self.contents)){
+                self.contents.pop().destroy();
+                self.setValue(self.getValue());
+                self._adjustInputWidth();
+            }
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_ERROR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function(){
+            self.fireEvent(BI.RecordEditor.EVENT_EMPTY, arguments);
+        });
+        BI.createWidget({
+            type: "bi.inline",
+            element: this,
+            items: [this.textContainer, this.editor]
+        });
+        BI.Resizers.add(this.getName(), BI.bind(this._adjustInputWidth, this));
+        this._adjustInputWidth();
+    },
+
+    _adjustInputWidth: function(){
+        BI.nextTick(BI.bind(function(){
+            this.editor.element.css("width", this.element.width() - this.textContainer.element.outerWidth() - 10);
+        }, this));
+    },
+
+    _checkInputState: function(){
+        if(BI.isEmpty(this.contents)){
+            this.editor.enableWarterMark();
+        } else {
+            this.editor.disableWarterMark();
+        }
+    },
+
+    focus: function(){
+        this.editor.focus();
+    },
+
+    blur: function(){
+        this.editor.blur();
+    },
+
+    isValid : function() {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function(text){
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function(){
+        return this.editor.getErrorText();
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function(){
+        var values = BI.map(this.contents, function(i, lb){
+            return lb.getText();
+        });
+        if(BI.isNotEmptyString(this.editor.getValue())){
+            return values.concat([this.editor.getValue()]);
+        }
+        return values;
+    },
+
+    setState: function(v){
+        BI.StateEditor.superclass.setValue.apply(this, arguments);
+        v =  BI.isArray(v) ? v : (v == "" ? [] : [v]);
+        var contents = this.contents = [];
+        BI.each(v, function(i, lb){
+            contents.push(BI.createWidget({
+                type: "bi.label",
+                height: 25,
+                cls: "record-editor-text",
+                text: lb
+            }))
+        });
+        this.textContainer.empty();
+        this.textContainer.populate(contents);
+        this.editor.isValid() && this.editor.setValue("");
+        this._checkInputState();
+        this._adjustInputWidth();
+    },
+
+    destroy: function(){
+        BI.Resizers.remove(this.getName());
+        BI.RecordEditor.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.RecordEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.RecordEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.RecordEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.RecordEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.RecordEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+
+BI.RecordEditor.EVENT_START = "EVENT_START";
+BI.RecordEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.RecordEditor.EVENT_STOP = "EVENT_STOP";
+BI.RecordEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.RecordEditor.EVENT_VALID = "EVENT_VALID";
+BI.RecordEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.RecordEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.RecordEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.RecordEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.RecordEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.record_editor", BI.RecordEditor);/**
+ * 带标记的文本框
+ * Created by GUY on 2016/1/25.
+ * @class BI.ShelterEditor
+ * @extends BI.Single
+ */
+BI.ShelterEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.ShelterEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-shelter-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30,
+            textAlign: "left"
+        })
+    },
+
+    _init: function () {
+        BI.ShelterEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "shelter-editor-text",
+            textAlign: o.textAlign,
+            height: o.height,
+            hgap: 4
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.text,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.text.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_CLICK_LABEL);
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.ShelterEditor.EVENT_KEY_DOWN, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self._checkText();
+            self.fireEvent(BI.ShelterEditor.EVENT_CONFIRM, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self._checkText();
+            self.fireEvent(BI.ShelterEditor.EVENT_ERROR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.ShelterEditor.EVENT_EMPTY, arguments);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+        self._checkText();
+    },
+
+    _checkText: function () {
+        var o = this.options;
+        if (this.editor.getValue() === "") {
+            this.text.setValue(o.watermark || "");
+            this.text.element.addClass("bi-water-mark");
+        } else {
+            this.text.setValue(this.editor.getValue());
+            this.text.element.removeClass("bi-water-mark");
+        }
+    },
+
+    _showInput: function () {
+        this.editor.visible();
+        this.text.invisible();
+    },
+
+    _showHint: function () {
+        this.editor.invisible();
+        this.text.visible();
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+        this._checkText();
+    },
+
+    doRedMark: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+        this._checkText();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.text.getValue();
+    },
+
+    setState: function (v) {
+        this._showHint();
+        this.text.setValue(v);
+    }
+});
+BI.ShelterEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.ShelterEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.ShelterEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.ShelterEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.ShelterEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.ShelterEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.ShelterEditor.EVENT_START = "EVENT_START";
+BI.ShelterEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.ShelterEditor.EVENT_STOP = "EVENT_STOP";
+BI.ShelterEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.ShelterEditor.EVENT_VALID = "EVENT_VALID";
+BI.ShelterEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.ShelterEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.ShelterEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.ShelterEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.ShelterEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.shelter_editor", BI.ShelterEditor);/**
+ * 带标记的文本框
+ * Created by GUY on 2015/8/28.
+ * @class BI.SignEditor
+ * @extends BI.Single
+ */
+BI.SignEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.SignEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-sign-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SignEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "sign-editor-text",
+            textAlign: "left",
+            height: o.height,
+            hgap: 4,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.selectAll();
+            }
+        });
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SignEditor.EVENT_CLICK_LABEL)
+            });
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.text,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SignEditor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SignEditor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SignEditor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SignEditor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SignEditor.EVENT_KEY_DOWN, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SignEditor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self._checkText();
+            self.fireEvent(BI.SignEditor.EVENT_CONFIRM, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SignEditor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SignEditor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SignEditor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SignEditor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self._checkText();
+            self.fireEvent(BI.SignEditor.EVENT_ERROR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SignEditor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SignEditor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SignEditor.EVENT_EMPTY, arguments);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+        self._checkText();
+    },
+
+    _checkText: function () {
+        var o = this.options;
+        if (this.editor.getValue() === "") {
+            this.text.setValue(o.watermark || "");
+            this.text.element.addClass("bi-water-mark");
+        } else {
+            this.text.setValue(this.editor.getValue());
+            this.text.element.removeClass("bi-water-mark");
+        }
+    },
+
+    _showInput: function () {
+        this.editor.visible();
+        this.text.invisible();
+    },
+
+    _showHint: function () {
+        this.editor.invisible();
+        this.text.visible();
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+        this._checkText();
+    },
+
+    doRedMark: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setValid: function(v){
+        BI.SignEditor.superclass.setValid.apply(this, arguments);
+        this.editor.setValid(v);
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+        this._checkText();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.text.getValue();
+    },
+
+    setState: function (v) {
+        this._showHint();
+        this.text.setValue(v);
+    }
+});
+BI.SignEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SignEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SignEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SignEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SignEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SignEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SignEditor.EVENT_START = "EVENT_START";
+BI.SignEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SignEditor.EVENT_STOP = "EVENT_STOP";
+BI.SignEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SignEditor.EVENT_VALID = "EVENT_VALID";
+BI.SignEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SignEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SignEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SignEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SignEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.sign_editor", BI.SignEditor);/**
+ * guy
+ * 记录状态的输入框
+ * @class BI.StateEditor
+ * @extends BI.Single
+ */
+BI.StateEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.StateEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-state-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.StateEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "state-editor-infinite-text",
+            textAlign: "left",
+            height: o.height,
+            text: BI.i18nText("BI-Unrestricted"),
+            hgap: 4,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.setValue("");
+            }
+        });
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.StateEditor.EVENT_CLICK_LABEL);
+            });
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.text,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.StateEditor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.StateEditor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.StateEditor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.StateEditor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.StateEditor.EVENT_KEY_DOWN, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.StateEditor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self.fireEvent(BI.StateEditor.EVENT_CONFIRM, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.StateEditor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.StateEditor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.StateEditor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.StateEditor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.StateEditor.EVENT_ERROR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.StateEditor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.StateEditor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.StateEditor.EVENT_EMPTY, arguments);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+    },
+
+    doRedMark: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+    },
+
+    _showInput: function () {
+        this.editor.visible();
+        this.text.invisible();
+    },
+
+    _showHint: function () {
+        this.editor.invisible();
+        this.text.visible();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.editor.getValue().match(/[^\s]+/g);
+    },
+
+    setState: function (v) {
+        BI.StateEditor.superclass.setValue.apply(this, arguments);
+        if (BI.isNumber(v)) {
+            if (v === BI.Selection.All) {
+                this.text.setText(BI.i18nText("BI-Select_All"));
+                this.text.element.removeClass("state-editor-infinite-text");
+            } else if (v === BI.Selection.Multi) {
+                this.text.setText(BI.i18nText("BI-Select_Part"));
+                this.text.element.removeClass("state-editor-infinite-text");
+            } else {
+                this.text.setText(BI.i18nText("BI-Unrestricted"));
+                this.text.element.addClass("state-editor-infinite-text");
+            }
+            return;
+        }
+        if (!BI.isArray(v) || v.length === 1) {
+            this.text.setText(v);
+            this.text.setTitle(v);
+            this.text.element.removeClass("state-editor-infinite-text");
+        } else if (BI.isEmpty(v)) {
+            this.text.setText(BI.i18nText("BI-Unrestricted"));
+            this.text.element.addClass("state-editor-infinite-text");
+        } else {
+            this.text.setText(BI.i18nText("BI-Select_Part"));
+            this.text.element.removeClass("state-editor-infinite-text");
+        }
+    }
+});
+BI.StateEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.StateEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.StateEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.StateEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.StateEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.StateEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.StateEditor.EVENT_START = "EVENT_START";
+BI.StateEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.StateEditor.EVENT_STOP = "EVENT_STOP";
+BI.StateEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.StateEditor.EVENT_VALID = "EVENT_VALID";
+BI.StateEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.StateEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.StateEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.StateEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.StateEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.state_editor", BI.StateEditor);/**
+ * 无限制-已选择状态输入框
+ * Created by GUY on 2016/5/18.
+ * @class BI.SimpleStateEditor
+ * @extends BI.Single
+ */
+BI.SimpleStateEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.SimpleStateEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-simple-state-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SimpleStateEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "state-editor-infinite-text",
+            textAlign: "left",
+            height: o.height,
+            text: BI.i18nText("BI-Unrestricted"),
+            hgap: 4,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.setValue("");
+            }
+        });
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SimpleStateEditor.EVENT_CLICK_LABEL);
+            });
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.text,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_FOCUS, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_BLUR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_CLICK, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_KEY_DOWN, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_VALID, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self.fireEvent(BI.SimpleStateEditor.EVENT_CONFIRM, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_START, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_PAUSE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_STOP, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_SPACE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_ERROR, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_ENTER, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_RESTRICT, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SimpleStateEditor.EVENT_EMPTY, arguments);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+    },
+
+    doRedMark: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) {
+            return;
+        }
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+    },
+
+    _showInput: function () {
+        this.editor.visible();
+        this.text.invisible();
+    },
+
+    _showHint: function () {
+        this.editor.invisible();
+        this.text.visible();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.editor.getValue().match(/[^\s]+/g);
+    },
+
+    setState: function (v) {
+        BI.SimpleStateEditor.superclass.setValue.apply(this, arguments);
+        if (BI.isNumber(v)) {
+            if (v === BI.Selection.All) {
+                this.text.setText(BI.i18nText("BI-Aleady_Selected"));
+                this.text.element.removeClass("state-editor-infinite-text");
+            } else if (v === BI.Selection.Multi) {
+                this.text.setText(BI.i18nText("BI-Aleady_Selected"));
+                this.text.element.removeClass("state-editor-infinite-text");
+            } else {
+                this.text.setText(BI.i18nText("BI-Unrestricted"));
+                this.text.element.addClass("state-editor-infinite-text");
+            }
+            return;
+        }
+        if (!BI.isArray(v) || v.length === 1) {
+            this.text.setText(v);
+            this.text.setTitle(v);
+            this.text.element.removeClass("state-editor-infinite-text");
+        } else if (BI.isEmpty(v)) {
+            this.text.setText(BI.i18nText("BI-Unrestricted"));
+            this.text.element.addClass("state-editor-infinite-text");
+        } else {
+            this.text.setText(BI.i18nText("BI-Aleady_Selected"));
+            this.text.element.removeClass("state-editor-infinite-text");
+        }
+    }
+});
+BI.SimpleStateEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SimpleStateEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SimpleStateEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SimpleStateEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SimpleStateEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SimpleStateEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SimpleStateEditor.EVENT_START = "EVENT_START";
+BI.SimpleStateEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SimpleStateEditor.EVENT_STOP = "EVENT_STOP";
+BI.SimpleStateEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SimpleStateEditor.EVENT_VALID = "EVENT_VALID";
+BI.SimpleStateEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SimpleStateEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SimpleStateEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SimpleStateEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SimpleStateEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.simple_state_editor", BI.SimpleStateEditor);/**
+ * 倒立的Branch
+ * @class BI.HandStandBranchExpander
+ * @extend BI.Widget
+ * create by young
+ */
+BI.HandStandBranchExpander = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.HandStandBranchExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-handstand-branch-expander",
+            direction: BI.Direction.Top,
+            logic: {
+                dynamic: true
+            },
+            el: {type: "bi.label"},
+            popup: {}
+        })
+    },
+
+    _init: function () {
+        BI.HandStandBranchExpander.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this._initExpander();
+        this._initBranchView();
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, {
+                type: "bi.center_adapt",
+                items: [this.expander]
+            }, this.branchView)
+        }))));
+    },
+
+    _initExpander: function () {
+        var self = this, o = this.options;
+        this.expander = BI.createWidget(o.el);
+        this.expander.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _initBranchView: function () {
+        var self = this, o = this.options;
+        this.branchView = BI.createWidget(o.popup, {});
+        this.branchView.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    populate: function (items) {
+        this.branchView.populate.apply(this.branchView, arguments);
+    },
+
+    getValue: function () {
+        return this.branchView.getValue();
+    }
+});
+BI.HandStandBranchExpander.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.handstand_branch_expander", BI.HandStandBranchExpander);/**
+ * @class BI.BranchExpander
+ * @extend BI.Widget
+ * create by young
+ */
+BI.BranchExpander = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BranchExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-branch-expander",
+            direction: BI.Direction.Left,
+            logic: {
+                dynamic: true
+            },
+            el: {},
+            popup: {}
+        })
+    },
+
+    _init: function () {
+        BI.BranchExpander.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this._initExpander();
+        this._initBranchView();
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.expander, this.branchView)
+        }))));
+    },
+
+    _initExpander: function () {
+        var self = this, o = this.options;
+        this.expander = BI.createWidget(o.el, {
+            type: "bi.label",
+            width: 30,
+            height: "100%"
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _initBranchView: function () {
+        var self = this, o = this.options;
+        this.branchView = BI.createWidget(o.popup, {});
+        this.branchView.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    populate: function (items) {
+        this.branchView.populate.apply(this.branchView, arguments);
+    },
+
+    getValue: function () {
+        return this.branchView.getValue();
+    }
+});
+BI.BranchExpander.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.branch_expander", BI.BranchExpander);/**
+ * 有确定取消按钮的弹出层
+ * @class BI.BarFloatSection
+ * @extends BI.FloatSection
+ * @abstract
+ */
+BI.BarFloatSection = BI.inherit(BI.FloatSection, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BarFloatSection.superclass._defaultConfig.apply(this, arguments), {
+            btns: [BI.i18nText(BI.i18nText("BI-Sure")), BI.i18nText("BI-Cancel")]
+        })
+    },
+
+    _init: function () {
+        BI.BarFloatSection.superclass._init.apply(this, arguments);
+        var self = this;
+        var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"];
+        flatten = BI.makeObject(flatten, true);
+        BI.each(this.constructor.caller.caller.caller.caller.prototype, function (key) {
+            if (flatten[key]) {
+                return;
+            }
+            var f = self[key];
+            if (BI.isFunction(f)) {
+                self[key] = BI.bind(function () {
+                    if (this.model._start === true) {
+                        this._F.push({f: f, arg: arguments});
+                        return;
+                    }
+                    return f.apply(this, arguments);
+                }, self);
+            }
+        })
+    },
+
+    rebuildSouth: function (south) {
+        var self = this, o = this.options;
+        this.sure = BI.createWidget({
+            type: 'bi.button',
+            text: this.options.btns[0],
+            height: 30,
+            value: 0,
+            handler: function (v) {
+                self.end();
+                self.close(v);
+            }
+        });
+        this.cancel = BI.createWidget({
+            type: 'bi.button',
+            text: this.options.btns[1],
+            height: 30,
+            value: 1,
+            level: 'ignore',
+            handler: function (v) {
+                self.close(v);
+            }
+        });
+        BI.createWidget({
+            type: 'bi.right_vertical_adapt',
+            element: south,
+            hgap: 5,
+            items: [this.cancel, this.sure]
+        });
+    }
+});
+
+/**
+ * 有确定取消按钮的弹出层
+ * @class BI.BarPopoverSection
+ * @extends BI.PopoverSection
+ * @abstract
+ */
+BI.BarPopoverSection = BI.inherit(BI.PopoverSection, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BarPopoverSection.superclass._defaultConfig.apply(this, arguments), {
+            btns: [BI.i18nText(BI.i18nText("BI-Sure")), BI.i18nText(BI.i18nText("BI-Cancel"))]
+        })
+    },
+
+    _init: function () {
+        BI.BarPopoverSection.superclass._init.apply(this, arguments);
+    },
+
+    rebuildSouth: function (south) {
+        var self = this;
+        this.sure = BI.createWidget({
+            type: 'bi.button',
+            text: this.options.btns[0],
+            height: 30,
+            value: 0,
+            handler: function (v) {
+                self.end();
+                self.close(v);
+            }
+        });
+        this.cancel = BI.createWidget({
+            type: 'bi.button',
+            text: this.options.btns[1],
+            height: 30,
+            value: 1,
+            level: 'ignore',
+            handler: function (v) {
+                self.close(v);
+            }
+        });
+        BI.createWidget({
+            type: 'bi.right_vertical_adapt',
+            element: south,
+            hgap: 5,
+            items: [this.cancel, this.sure]
+        });
+    }
+});/**
+ * 下拉框弹出层的多选版本,toolbar带有若干按钮, zIndex在1000w
+ * @class BI.MultiPopupView
+ * @extends BI.Widget
+ */
+
+BI.MultiPopupView = BI.inherit(BI.PopupView, {
+
+    _defaultConfig: function () {
+        var conf = BI.MultiPopupView.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-multi-list-view",
+            buttons: [BI.i18nText("BI-Sure")]
+        })
+    },
+
+    _init: function () {
+        BI.MultiPopupView.superclass._init.apply(this, arguments);
+    },
+
+    _createToolBar: function () {
+        var o = this.options, self = this;
+        if (o.buttons.length === 0) {
+            return;
+        }
+
+        var text = [];          //构造[{text:content},……]
+        BI.each(o.buttons, function (idx, item) {
+            text.push({
+                text: item,
+                value: idx
+            })
+        });
+
+        this.buttongroup = BI.createWidget({
+            type: "bi.button_group",
+            cls: "list-view-toolbar",
+            height: 30,
+            items: BI.createItems(text, {
+                type: "bi.text_button",
+                once: false,
+                shadow: true,
+                isShadowShowingOnSelected: true
+            }),
+            layouts: [{
+                type: "bi.center",
+                hgap: 0,
+                vgap: 0
+            }]
+        });
+
+        this.buttongroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, value, obj);
+        });
+
+        return this.buttongroup;
+    }
+
+});
+
+BI.MultiPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON";
+
+$.shortcut("bi.multi_popup_view", BI.MultiPopupView);/**
+ * 可以理解为MultiPopupView和Panel两个面板的结合体
+ * @class BI.PopupPanel
+ * @extends BI.MultiPopupView
+ */
+
+BI.PopupPanel = BI.inherit(BI.MultiPopupView, {
+
+    _defaultConfig: function () {
+        var conf = BI.PopupPanel.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-popup-panel",
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.PopupPanel.superclass._init.apply(this, arguments);
+    },
+
+    _createTool: function () {
+        var self = this, o = this.options;
+        var close = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "close-h-font",
+            width: 25,
+            height: 25
+        });
+        close.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.setVisible(false);
+            self.fireEvent(BI.PopupPanel.EVENT_CLOSE);
+        });
+        return BI.createWidget({
+            type: "bi.htape",
+            cls: "popup-panel-title",
+            height: 25,
+            items: [{
+                el: {
+                    type: "bi.label",
+                    textAlign: "left",
+                    text: o.title,
+                    height: 25,
+                    lgap: 10
+                }
+            }, {
+                el: close,
+                width: 25
+            }]
+        });
+    }
+});
+
+BI.PopupPanel.EVENT_CHANGE = "EVENT_CHANGE";
+BI.PopupPanel.EVENT_CLOSE = "EVENT_CLOSE";
+BI.PopupPanel.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON";
+
+$.shortcut("bi.popup_panel", BI.PopupPanel);/**
+ * list面板
+ *
+ * Created by GUY on 2015/10/30.
+ * @class BI.ListPane
+ * @extends BI.Pane
+ */
+BI.ListPane = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        var conf = BI.ListPane.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-list-pane",
+            logic: {
+                dynamic: true
+            },
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            vgap: 0,
+            hgap: 0,
+            items: [],
+            itemsCreator: BI.emptyFn,
+            hasNext: BI.emptyFn,
+            onLoaded: BI.emptyFn,
+            el: {
+                type: "bi.button_group"
+            }
+        })
+    },
+    _init: function () {
+        BI.ListPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button_group = BI.createWidget(o.el, {
+            type: "bi.button_group",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            behaviors: {},
+            items: o.items,
+            itemsCreator: function (op, calback) {
+                if (op.times === 1) {
+                    self.empty();
+                    BI.nextTick(function () {
+                        self.loading()
+                    });
+                }
+                o.itemsCreator(op, function () {
+                    calback.apply(self, arguments);
+                    op.times === 1 && BI.nextTick(function () {
+                        self.loaded();
+                    });
+                });
+            },
+            hasNext: o.hasNext,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.ListPane.EVENT_CHANGE, value, obj);
+            }
+        });
+        this.check();
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Top), BI.extend({
+            scrolly: true,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            vgap: o.vgap,
+            hgap: o.hgap
+        }, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Top, this.button_group)
+        }))));
+    },
+
+    hasPrev: function () {
+        return this.button_group.hasPrev && this.button_group.hasPrev();
+    },
+
+    hasNext: function () {
+        return this.button_group.hasNext && this.button_group.hasNext();
+    },
+
+    prependItems: function (items) {
+        this.options.items = items.concat(this.options.items);
+        this.button_group.prependItems.apply(this.button_group, arguments);
+        this.check();
+    },
+
+    addItems: function (items) {
+        this.options.items = this.options.items.concat(items);
+        this.button_group.addItems.apply(this.button_group, arguments);
+        this.check();
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options;
+        if (arguments.length === 0 && (BI.isFunction(this.button_group.attr("itemsCreator")))) {//接管loader的populate方法
+            this.button_group.attr("itemsCreator").apply(this, [{times: 1}, function () {
+                if (arguments.length === 0) {
+                    throw new Error("参数不能为空");
+                }
+                self.populate.apply(self, arguments);
+            }]);
+            return;
+        }
+        BI.ListPane.superclass.populate.apply(this, arguments);
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    doBehavior: function () {
+        this.button_group.doBehavior.apply(this.button_group, arguments);
+    },
+
+    setNotSelectedValue: function () {
+        this.button_group.setNotSelectedValue.apply(this.button_group, arguments);
+    },
+
+    getNotSelectedValue: function () {
+        return this.button_group.getNotSelectedValue();
+    },
+
+    setValue: function () {
+        this.button_group.setValue.apply(this.button_group, arguments);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue.apply(this.button_group, arguments);
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.button_group.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.button_group.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.button_group.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.button_group.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.button_group.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.button_group.getNodeByValue(value);
+    }
+});
+BI.ListPane.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.list_pane", BI.ListPane);/**
+ * 带有标题栏的pane
+ * @class BI.Panel
+ * @extends BI.Widget
+ */
+BI.Panel = BI.inherit(BI.Widget,{
+    _defaultConfig : function(){
+        return BI.extend(BI.Panel.superclass._defaultConfig.apply(this,arguments),{
+            baseCls: "bi-panel",
+            title:"",
+            titleButtons:[],
+            el:{},
+            logic:{
+                dynamic: false
+            }
+        });
+    },
+
+    _init:function(){
+        BI.Panel.superclass._init.apply(this,arguments);
+        var o = this.options;
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("vertical", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("top", this._createTitle()
+                ,this.options.el)
+        }))));
+    },
+
+    _createTitle:function(){
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "panel-title-text",
+            text: o.title,
+            height: 30
+        });
+
+        this.button_group = BI.createWidget({
+            type:"bi.button_group",
+            items: o.titleButtons,
+            layouts: [{
+                type: "bi.center_adapt",
+                lgap:10
+            }]
+        });
+
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function(){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function(value, obj){
+            self.fireEvent(BI.Panel.EVENT_CHANGE, value, obj);
+        });
+
+        return {
+            el: {
+                type: "bi.left_right_vertical_adapt",
+                cls: "panel-title",
+                height: 30,
+                items: {
+                    left: [this.text],
+                    right: [this.button_group]
+                },
+                lhgap: 10,
+                rhgap: 10
+            },
+            height: 30
+        };
+    },
+
+    setTitle: function(title){
+        this.text.setValue(title);
+    }
+});
+BI.Panel.EVENT_CHANGE = "Panel.EVENT_CHANGE";
+
+$.shortcut("bi.panel",BI.Panel);/**
+ * 选择列表
+ *
+ * Created by GUY on 2015/11/1.
+ * @class BI.SelectList
+ * @extends BI.Widget
+ */
+BI.SelectList = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-list",
+            direction: BI.Direction.Top,//toolbar的位置
+            logic: {
+                dynamic: true
+            },
+            items: [],
+            itemsCreator: BI.emptyFn,
+            hasNext: BI.emptyFn,
+            onLoaded: BI.emptyFn,
+            toolbar: {
+                type: "bi.multi_select_bar"
+            },
+            el: {
+                type: "bi.list_pane"
+            }
+        })
+    },
+    _init: function () {
+        BI.SelectList.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        //全选
+        this.toolbar = BI.createWidget(o.toolbar);
+        this.toolbar.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            var isAllSelected = this.isSelected();
+            if (type === BI.Events.CLICK) {
+                self.setAllSelected(isAllSelected);
+                self.fireEvent(BI.SelectList.EVENT_CHANGE, value, obj);
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.list = BI.createWidget(o.el, {
+            type: "bi.list_pane",
+            items: o.items,
+            itemsCreator: function (op, callback) {
+                op.times === 1 && self.toolbar.setVisible(false);
+                o.itemsCreator(op, function (items) {
+                    callback.apply(self, arguments);
+                    if (op.times === 1) {
+                        self.toolbar.setVisible(items && items.length > 0);
+                        self.toolbar.setEnable(items && items.length > 0);
+                    }
+                    self._checkAllSelected();
+                });
+            },
+            onLoaded: o.onLoaded,
+            hasNext: o.hasNext
+        });
+
+        this.list.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (type === BI.Events.CLICK) {
+                self._checkAllSelected();
+                self.fireEvent(BI.SelectList.EVENT_CHANGE, value, obj);
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({
+            scrolly: true
+        }, o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.toolbar, this.list)
+        }))));
+
+        if (o.items.length <= 0) {
+            this.toolbar.setVisible(false);
+            this.toolbar.setEnable(false);
+        }
+    },
+
+    _checkAllSelected: function () {
+        var selectLength = this.list.getValue().length;
+        var notSelectLength = this.getAllLeaves().length - selectLength;
+        var hasNext = this.list.hasNext();
+        var isAlreadyAllSelected = this.toolbar.isSelected();
+        var isHalf = selectLength > 0 && (notSelectLength > 0 || (!isAlreadyAllSelected && hasNext));
+        isHalf = isHalf || (notSelectLength > 0 && hasNext && isAlreadyAllSelected);
+        this.toolbar.setHalfSelected(isHalf);
+        !isHalf && this.toolbar.setSelected(selectLength > 0 && notSelectLength <= 0 && (!hasNext || isAlreadyAllSelected));
+    },
+
+    setAllSelected: function (v) {
+        BI.each(this.getAllButtons(), function (i, btn) {
+            (btn.setSelected || btn.setAllSelected).apply(btn, [v]);
+        });
+        this.toolbar.setSelected(v);
+        this.toolbar.setHalfSelected(false);
+    },
+
+    setToolBarVisible: function (b) {
+        this.toolbar.setVisible(b);
+    },
+
+    isAllSelected: function () {
+        return this.toolbar.isSelected();
+    },
+
+    hasPrev: function () {
+        return this.list.hasPrev();
+    },
+
+    hasNext: function () {
+        return this.list.hasNext();
+    },
+
+    prependItems: function (items) {
+        this.list.prependItems.apply(this.list, arguments);
+    },
+
+    addItems: function (items) {
+        this.list.addItems.apply(this.list, arguments);
+    },
+
+    setValue: function (data) {
+        var selectAll = data.type === BI.ButtonGroup.CHOOSE_TYPE_ALL;
+        this.setAllSelected(selectAll);
+        this.list[selectAll ? "setNotSelectedValue" : "setValue"](data.value);
+        this._checkAllSelected();
+    },
+
+    getValue: function () {
+        if (this.isAllSelected() === false) {
+            return {
+                type: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                value: this.list.getValue(),
+                assist: this.list.getNotSelectedValue()
+            };
+        } else {
+            return {
+                type: BI.ButtonGroup.CHOOSE_TYPE_ALL,
+                value: this.list.getNotSelectedValue(),
+                assist: this.list.getValue()
+            };
+        }
+    },
+
+    empty: function () {
+        this.list.empty();
+    },
+
+    populate: function (items) {
+        this.toolbar.setVisible(!BI.isEmptyArray(items));
+        this.toolbar.setEnable(!BI.isEmptyArray(items));
+        this.list.populate.apply(this.list, arguments);
+        this._checkAllSelected();
+    },
+
+    resetHeight: function (h) {
+        var toolHeight = ( this.toolbar.element.outerHeight() || 25) * ( this.toolbar.isVisible() ? 1 : 0);
+        this.list.resetHeight ? this.list.resetHeight(h - toolHeight) :
+            this.list.element.css({"max-height": h - toolHeight + "px"})
+    },
+
+    doBehavior: function () {
+        this.list.doBehavior.apply(this.list, arguments);
+    },
+
+    setNotSelectedValue: function () {
+        this.list.setNotSelectedValue.apply(this.list, arguments);
+        this._checkAllSelected();
+    },
+
+    getNotSelectedValue: function () {
+        return this.list.getNotSelectedValue();
+    },
+
+    getAllButtons: function () {
+        return this.list.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.list.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.list.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.list.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.list.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.list.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.list.getNodeByValue(value);
+    }
+});
+BI.SelectList.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_list", BI.SelectList);/**
+ * Created by roy on 15/11/6.
+ */
+BI.LazyLoader = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LazyLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-lazy-loader",
+            el: {}
+        })
+    },
+
+    _init: function () {
+        var self = this, o = this.options;
+        BI.LazyLoader.superclass._init.apply(this, arguments);
+        var all = o.items.length;
+        this.loader = BI.createWidget({
+            type: "bi.loader",
+            element: this,
+            //下面是button_group的属性
+            el: o.el,
+
+            itemsCreator: function (options, populate) {
+                populate(self._getNextItems(options));
+            },
+            hasNext: function (option) {
+                return option.count < all;
+            }
+        });
+
+        this.loader.on(BI.Loader.EVENT_CHANGE, function (obj) {
+            self.fireEvent(BI.LazyLoader.EVENT_CHANGE, obj)
+        })
+    },
+    _getNextItems: function (options) {
+        var self = this, o = this.options;
+        var lastNum = o.items.length - BICst.PAGE_COUNT * (options.times - 1);
+        var lastItems = BI.last(o.items, lastNum);
+        var nextItems = BI.first(lastItems, BICst.PAGE_COUNT);
+        return nextItems;
+    },
+
+    populate: function (items) {
+        this.loader.populate(items);
+    },
+
+    addItems: function (items) {
+        this.loader.addItems(items);
+    },
+
+    empty: function () {
+        this.loader.empty();
+    },
+
+    doBehavior: function () {
+        this.loader.doBehavior();
+    },
+
+    setNotSelectedValue: function () {
+        this.loader.setNotSelectedValue.apply(this.loader, arguments);
+    },
+
+    getNotSelectedValue: function () {
+        return this.loader.getNotSelectedValue();
+    },
+
+    setValue: function () {
+        this.loader.setValue.apply(this.loader, arguments);
+    },
+
+    getValue: function () {
+        return this.loader.getValue.apply(this.loader, arguments);
+    },
+
+    getAllButtons: function () {
+        return this.loader.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.loader.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.loader.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.loader.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.loader.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.loader.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.loader.getNodeByValue(value);
+    }
+});
+BI.LazyLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.lazy_loader", BI.LazyLoader);/**
+ * 恶心的加载控件, 为解决排序问题引入的控件
+ *
+ * Created by GUY on 2015/11/12.
+ * @class BI.ListLoader
+ * @extends BI.Widget
+ */
+BI.ListLoader = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ListLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-list-loader",
+
+            isDefaultInit: true,//是否默认初始化数据
+
+            //下面是button_group的属性
+            el: {
+                type: "bi.button_group"
+            },
+
+            items: [],
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn,
+
+            //下面是分页信息
+            count: false,
+            next: {},
+            hasNext: BI.emptyFn
+        })
+    },
+
+    _nextLoad: function () {
+        var self = this, o = this.options;
+        this.next.setLoading();
+        o.itemsCreator.apply(this, [{times: ++this.times}, function () {
+            self.next.setLoaded();
+            self.addItems.apply(self, arguments);
+        }]);
+    },
+
+    _init: function () {
+        BI.ListLoader.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (o.itemsCreator === false) {
+            o.next = false;
+        }
+
+        this.button_group = BI.createWidget(o.el, {
+            type: "bi.button_group",
+            element: this,
+            chooseType: 0,
+            items: o.items,
+            behaviors: {},
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.ListLoader.EVENT_CHANGE, obj);
+            }
+        });
+
+        if (o.next !== false) {
+            this.next = BI.createWidget(BI.extend({
+                type: "bi.loading_bar"
+            }, o.next));
+            this.next.on(BI.Controller.EVENT_CHANGE, function (type) {
+                if (type === BI.Events.CLICK) {
+                    self._nextLoad();
+                }
+            })
+        }
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.next]
+        });
+
+        o.isDefaultInit && BI.isEmpty(o.items) && BI.nextTick(BI.bind(function () {
+            this.populate();
+        }, this));
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+    },
+
+    hasNext: function () {
+        var o = this.options;
+        if (BI.isNumber(o.count)) {
+            return this.count < o.count;
+        }
+        return !!o.hasNext.apply(this, [{
+            times: this.times,
+            count: this.count
+        }])
+    },
+
+    addItems: function (items) {
+        this.count += items.length;
+        if (BI.isObject(this.next)) {
+            if (this.hasNext()) {
+                this.options.items = this.options.items.concat(items);
+                this.next.setLoaded();
+            } else {
+                this.next.setEnd();
+            }
+        }
+        this.button_group.addItems.apply(this.button_group, arguments);
+        this.next.element.appendTo(this.element);
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options;
+        if (arguments.length === 0 && (BI.isFunction(o.itemsCreator))) {
+            o.itemsCreator.apply(this, [{times: 1}, function () {
+                if (arguments.length === 0) {
+                    throw new Error("参数不能为空");
+                }
+                self.populate.apply(self, arguments);
+                o.onLoaded();
+            }]);
+            return;
+        }
+        this.options.items = items;
+        this.times = 1;
+        this.count = 0;
+        this.count += items.length;
+        if (BI.isObject(this.next)) {
+            if (this.hasNext()) {
+                this.next.setLoaded();
+            } else {
+                this.next.invisible();
+            }
+        }
+        BI.DOM.hang([this.next]);
+        this.button_group.populate.apply(this.button_group, arguments);
+        this.next.element.appendTo(this.element);
+    },
+
+    empty: function () {
+        BI.DOM.hang([this.next]);
+        this.button_group.empty();
+        this.next.element.appendTo(this.element);
+        BI.each([this.next], function (i, ob) {
+            ob && ob.setVisible(false);
+        });
+    },
+
+    doBehavior: function () {
+        this.button_group.doBehavior.apply(this.button_group, arguments);
+    },
+
+    setNotSelectedValue: function () {
+        this.button_group.setNotSelectedValue.apply(this.button_group, arguments);
+    },
+
+    getNotSelectedValue: function () {
+        return this.button_group.getNotSelectedValue();
+    },
+
+    setValue: function () {
+        this.button_group.setValue.apply(this.button_group, arguments);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue.apply(this.button_group, arguments);
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.button_group.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.button_group.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.button_group.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.button_group.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.button_group.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.button_group.getNodeByValue(value);
+    }
+});
+BI.ListLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.list_loader", BI.ListLoader);/**
+ * Created by GUY on 2016/4/29.
+ *
+ * @class BI.SortList
+ * @extends BI.Widget
+ */
+BI.SortList = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SortList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sort-list",
+
+            isDefaultInit: true,//是否默认初始化数据
+
+            //下面是button_group的属性
+            el: {
+                type: "bi.button_group"
+            },
+
+            items: [],
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn,
+
+            //下面是分页信息
+            count: false,
+            next: {},
+            hasNext: BI.emptyFn
+
+            //containment: this.element,
+            //connectWith: ".bi-sort-list",
+        })
+    },
+
+    _init: function () {
+        BI.SortList.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.loader = BI.createWidget({
+            type: "bi.list_loader",
+            element: this,
+            isDefaultInit: o.isDefaultInit,
+            el: o.el,
+            items: this._formatItems(o.items),
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (items) {
+                    callback(self._formatItems(items));
+                });
+            },
+            onLoaded: o.onLoaded,
+            count: o.count,
+            next: o.next,
+            hasNext: o.hasNext
+        });
+        this.loader.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.SortList.EVENT_CHANGE, value, obj);
+            }
+        });
+
+        this.loader.element.sortable({
+            containment: o.containment || this.element,
+            connectWith: o.connectWith || ".bi-sort-list",
+            items: ".sort-item",
+            cursor: "drag",
+            tolerance: "intersect",
+            placeholder: {
+                element: function ($currentItem) {
+                    var holder = BI.createWidget({
+                        type: "bi.label",
+                        cls: "bi-sortable-holder",
+                        height: $currentItem.outerHeight()
+                    });
+                    holder.element.css({
+                        "margin-left": $currentItem.css("margin-left"),
+                        "margin-right": $currentItem.css("margin-right"),
+                        "margin-top": $currentItem.css("margin-top"),
+                        "margin-bottom": $currentItem.css("margin-bottom"),
+                        "margin": $currentItem.css("margin")
+                    });
+                    return holder.element;
+                },
+                update: function () {
+
+                }
+            },
+            start: function (event, ui) {
+
+            },
+            stop: function (event, ui) {
+                self.fireEvent(BI.SortList.EVENT_CHANGE);
+            },
+            over: function (event, ui) {
+
+            }
+        });
+    },
+
+    _formatItems: function (items) {
+        BI.each(items, function (i, item) {
+            item = BI.stripEL(item);
+            item.cls = item.cls ? item.cls + " sort-item" : "sort-item";
+            item.attributes = {
+                sorted: item.value
+            };
+        });
+        return items;
+    },
+
+    hasNext: function () {
+        return this.loader.hasNext();
+    },
+
+    addItems: function (items) {
+        this.loader.addItems(items);
+    },
+
+    populate: function (items) {
+        this.loader.populate.apply(this.loader, arguments);
+    },
+
+    empty: function () {
+        this.loader.empty();
+    },
+
+    doBehavior: function () {
+        this.loader.doBehavior.apply(this.loader, arguments);
+    },
+
+    setNotSelectedValue: function () {
+        this.loader.setNotSelectedValue.apply(this.loader, arguments);
+    },
+
+    getNotSelectedValue: function () {
+        return this.loader.getNotSelectedValue();
+    },
+
+    setValue: function () {
+        this.loader.setValue.apply(this.loader, arguments);
+    },
+
+    getValue: function () {
+        return this.loader.getValue();
+    },
+
+    getAllButtons: function () {
+        return this.loader.getAllButtons();
+    },
+
+    getAllLeaves: function () {
+        return this.loader.getAllLeaves();
+    },
+
+    getSelectedButtons: function () {
+        return this.loader.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.loader.getNotSelectedButtons();
+    },
+
+    getIndexByValue: function (value) {
+        return this.loader.getIndexByValue(value);
+    },
+
+    getNodeById: function (id) {
+        return this.loader.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.loader.getNodeByValue(value);
+    },
+
+    getSortedValues: function () {
+        return this.loader.element.sortable("toArray", {attribute: "sorted"});
+    }
+});
+BI.SortList.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.sort_list", BI.SortList);/**
+ * 有总页数的分页控件
+ *
+ * Created by GUY on 2015/9/8.
+ * @class BI.AllPagger
+ * @extends BI.Widget
+ */
+BI.AllPagger = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.AllPagger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-all-pager",
+            width: 96,
+            height: 25,
+            pages: 1, //必选项
+            curr: 1 //初始化当前页, pages为数字时可用
+        })
+    },
+    _init: function () {
+        BI.AllPagger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.small_text_editor",
+            cls: "pager-editor",
+            validationChecker: function (v) {
+                return BI.isPositiveInteger(v);
+            },
+            hgap: 4,
+            vgap: 0,
+            value: o.curr,
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: 30,
+            height: o.height - 2
+        });
+        this.pager = BI.createWidget({
+            type: "bi.pager",
+            width: 36,
+            layouts: [{
+                type: "bi.horizontal",
+                hgap: 1,
+                vgap: 1
+            }],
+
+            dynamicShow: false,
+            pages: o.pages,
+            curr: o.curr,
+            groups: 0,
+
+            first: false,
+            last: false,
+            prev: {
+                type: "bi.icon_button",
+                value: "prev",
+                title: BI.i18nText("BI-Previous_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_First_Page"),
+                height: o.height - 2,
+                cls: "all-pager-prev column-pre-page-h-font"
+            },
+            next: {
+                type: "bi.icon_button",
+                value: "next",
+                title: BI.i18nText("BI-Next_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_Last_Page"),
+                height: o.height - 2,
+                cls: "all-pager-next column-next-page-h-font"
+            },
+
+            hasPrev: o.hasPrev,
+            hasNext: o.hasNext,
+            firstPage: o.firstPage,
+            lastPage: o.lastPage
+        });
+
+        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function () {
+            self.pager.setValue(BI.parseInt(self.editor.getValue()));
+            self.fireEvent(BI.AllPagger.EVENT_CHANGE);
+        });
+        this.pager.on(BI.Pager.EVENT_CHANGE, function () {
+            self.fireEvent(BI.AllPagger.EVENT_CHANGE);
+        });
+        this.pager.on(BI.Pager.EVENT_AFTER_POPULATE, function () {
+            self.editor.setValue(self.pager.getCurrentPage());
+        });
+
+        this.allPages = BI.createWidget({
+            type: "bi.label",
+            width: 30,
+            title: o.pages,
+            text: "/" + o.pages
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            columnSize: [30, "", 36],
+            items: [this.editor, this.allPages, this.pager]
+        })
+    },
+
+    setAllPages: function (v) {
+        this.allPages.setText("/" + v);
+        this.allPages.setTitle(v);
+        this.pager.setAllPages(v);
+    },
+
+    setValue: function (v) {
+        this.pager.setValue(v);
+    },
+
+    getCurrentPage: function () {
+        return this.pager.getCurrentPage();
+    },
+
+    hasPrev: function () {
+        return this.pager.hasPrev();
+    },
+
+    hasNext: function () {
+        return this.pager.hasNext();
+    },
+
+    populate: function () {
+        this.pager.populate();
+    }
+});
+BI.AllPagger.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.all_pager", BI.AllPagger);/**
+ * 显示页码的分页控件
+ *
+ * Created by GUY on 2016/6/30.
+ * @class BI.DirectionPager
+ * @extends BI.Widget
+ */
+BI.DirectionPager = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DirectionPager.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-direction-pager",
+            width: 108,
+            height: 25,
+            horizontal: {
+                pages: false, //总页数
+                curr: 1, //初始化当前页, pages为数字时可用
+
+                hasPrev: BI.emptyFn,
+                hasNext: BI.emptyFn,
+                firstPage: 1,
+                lastPage: BI.emptyFn
+            },
+            vertical: {
+                pages: false, //总页数
+                curr: 1, //初始化当前页, pages为数字时可用
+
+                hasPrev: BI.emptyFn,
+                hasNext: BI.emptyFn,
+                firstPage: 1,
+                lastPage: BI.emptyFn
+            }
+        })
+    },
+    _init: function () {
+        BI.DirectionPager.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var v = o.vertical, h = o.horizontal;
+        this._createVPager();
+        this._createHPager();
+        BI.createWidget({
+            type: "bi.absolute",
+            scrollable: false,
+            element: this,
+            items: [{
+                el: this.vpager,
+                top: 0,
+                left: -19
+            }, {
+                el: this.vlabel,
+                top: 0,
+                left: 16
+            }, {
+                el: this.hpager,
+                top: 0,
+                right: -19
+            }, {
+                el: this.hlabel,
+                top: 0,
+                right: 16
+            }]
+        });
+    },
+
+    _createVPager: function () {
+        var self = this, o = this.options;
+        var v = o.vertical;
+        this.vlabel = BI.createWidget({
+            type: "bi.label",
+            width: 20,
+            height: o.height,
+            value: v.curr,
+            title: v.curr
+        });
+        this.vpager = BI.createWidget({
+            type: "bi.pager",
+            width: 72,
+            layouts: [{
+                type: "bi.horizontal",
+                lgap: 20,
+                vgap: 1
+            }],
+
+            dynamicShow: false,
+            pages: v.pages,
+            curr: v.curr,
+            groups: 0,
+
+            first: false,
+            last: false,
+            prev: {
+                type: "bi.icon_button",
+                value: "prev",
+                title: BI.i18nText("BI-Up_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_First_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "direction-pager-prev column-pre-page-h-font"
+            },
+            next: {
+                type: "bi.icon_button",
+                value: "next",
+                title: BI.i18nText("BI-Down_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_Last_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "direction-pager-next column-next-page-h-font"
+            },
+
+            hasPrev: v.hasPrev,
+            hasNext: v.hasNext,
+            firstPage: v.firstPage,
+            lastPage: v.lastPage
+        });
+
+        this.vpager.on(BI.Pager.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DirectionPager.EVENT_CHANGE);
+        });
+        this.vpager.on(BI.Pager.EVENT_AFTER_POPULATE, function () {
+            self.vlabel.setValue(this.getCurrentPage());
+        });
+    },
+
+    _createHPager: function () {
+        var self = this, o = this.options;
+        var h = o.horizontal;
+        this.hlabel = BI.createWidget({
+            type: "bi.label",
+            width: 20,
+            height: o.height,
+            value: h.curr,
+            title: h.curr
+        });
+        this.hpager = BI.createWidget({
+            type: "bi.pager",
+            width: 72,
+            layouts: [{
+                type: "bi.horizontal",
+                rgap: 20,
+                vgap: 1
+            }],
+
+            dynamicShow: false,
+            pages: h.pages,
+            curr: h.curr,
+            groups: 0,
+
+            first: false,
+            last: false,
+            prev: {
+                type: "bi.icon_button",
+                value: "prev",
+                title: BI.i18nText("BI-Left_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_First_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "direction-pager-prev row-pre-page-h-font"
+            },
+            next: {
+                type: "bi.icon_button",
+                value: "next",
+                title: BI.i18nText("BI-Right_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_Last_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "direction-pager-next row-next-page-h-font"
+            },
+
+            hasPrev: h.hasPrev,
+            hasNext: h.hasNext,
+            firstPage: h.firstPage,
+            lastPage: h.lastPage
+        });
+
+        this.hpager.on(BI.Pager.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DirectionPager.EVENT_CHANGE);
+        });
+        this.hpager.on(BI.Pager.EVENT_AFTER_POPULATE, function () {
+            self.hlabel.setValue(this.getCurrentPage());
+        });
+    },
+
+    getVPage: function () {
+        return this.vpager.getCurrentPage();
+    },
+
+    getHPage: function () {
+        return this.hpager.getCurrentPage();
+    },
+
+    setVPage: function (v) {
+        this.vpager.setValue(v);
+        this.vlabel.setValue(v);
+        this.vlabel.setTitle(v);
+    },
+
+    setHPage: function (v) {
+        this.hpager.setValue(v);
+        this.hlabel.setValue(v);
+        this.hlabel.setTitle(v);
+    },
+
+    hasVNext: function () {
+        return this.vpager.hasNext();
+    },
+
+    hasHNext: function () {
+        return this.hpager.hasNext();
+    },
+
+    hasVPrev: function () {
+        return this.vpager.hasPrev();
+    },
+
+    hasHPrev: function () {
+        return this.hpager.hasPrev();
+    },
+
+    setHPagerVisible: function (b) {
+        this.hpager.setVisible(b);
+        this.hlabel.setVisible(b);
+    },
+
+    setVPagerVisible: function (b) {
+        this.vpager.setVisible(b);
+        this.vlabel.setVisible(b);
+    },
+
+    populate: function () {
+        this.vpager.populate();
+        this.hpager.populate();
+    },
+    
+    refresh: function () {
+        this.vpager.refresh();
+        this.hpager.refresh();
+    }
+});
+BI.DirectionPager.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.direction_pager", BI.DirectionPager);/**
+ * 显示页码的分页控件
+ *
+ * Created by GUY on 2016/2/17.
+ * @class BI.NumberPager
+ * @extends BI.Widget
+ */
+BI.NumberPager = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.NumberPager.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-number-pager",
+            width: 95,
+            height: 25,
+            pages: false, //总页数
+            curr: 1, //初始化当前页, pages为数字时可用
+
+            hasPrev: BI.emptyFn,
+            hasNext: BI.emptyFn,
+            firstPage: 1,
+            lastPage: BI.emptyFn
+        })
+    },
+    _init: function () {
+        BI.NumberPager.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.currentPage = o.curr;
+        this.label = BI.createWidget({
+            type: "bi.label",
+            height: o.height - 2,
+            value: this.currentPage
+        });
+        this.pager = BI.createWidget({
+            type: "bi.pager",
+            width: 36,
+            layouts: [{
+                type: "bi.horizontal",
+                hgap: 1,
+                vgap: 1
+            }],
+
+            dynamicShow: false,
+            pages: o.pages,
+            curr: o.curr,
+            groups: 0,
+
+            first: false,
+            last: false,
+            prev: {
+                type: "bi.icon_button",
+                value: "prev",
+                title: BI.i18nText("BI-Previous_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_First_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "number-pager-prev column-pre-page-h-font"
+            },
+            next: {
+                type: "bi.icon_button",
+                value: "next",
+                title: BI.i18nText("BI-Next_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_Last_Page"),
+                height: o.height - 2,
+                iconWidth: o.height - 2,
+                iconHeight: o.height - 2,
+                cls: "number-pager-next column-next-page-h-font"
+            },
+
+            hasPrev: o.hasPrev,
+            hasNext: o.hasNext,
+            firstPage: o.firstPage,
+            lastPage: o.lastPage
+        });
+
+        this.pager.on(BI.Pager.EVENT_CHANGE, function () {
+            if (self.getCurrentPage() !== self.pager.getCurrentPage()) {
+                self.currentPage = self.pager.getCurrentPage();
+                self.fireEvent(BI.NumberPager.EVENT_CHANGE);
+            }
+        });
+        this.pager.on(BI.Pager.EVENT_AFTER_POPULATE, function () {
+            self.label.setValue(self.pager.getCurrentPage());
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            columnSize: [20, "", 20, 36],
+            items: [{type: "bi.label", text: "第"}, this.label, {type: "bi.label", text: "页"}, this.pager]
+        })
+    },
+
+    getCurrentPage: function () {
+        return this.currentPage;
+    },
+
+    hasPrev: function () {
+        return this.pager.hasPrev();
+    },
+
+    hasNext: function () {
+        return this.pager.hasNext();
+    },
+
+    setValue: function (v) {
+        this.currentPage = v;
+        this.pager.setValue(v);
+    },
+
+    populate: function () {
+        this.pager.populate();
+    }
+});
+BI.NumberPager.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.number_pager", BI.NumberPager);/**
+ * 可以跳转的分页控件
+ *
+ * Created by GUY on 2015/9/8.
+ * @class BI.SkipPager
+ * @extends BI.Widget
+ */
+BI.SkipPager = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SkipPager.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-skip-pager",
+            width: 110,
+            height: 25,
+            pages: false, //总页数
+            curr: 1, //初始化当前页, pages为数字时可用
+
+            hasPrev: BI.emptyFn,
+            hasNext: BI.emptyFn,
+            firstPage: 1,
+            lastPage: BI.emptyFn
+        })
+    },
+    _init: function () {
+        BI.SkipPager.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.currentPage = o.curr;
+        this.editor = BI.createWidget({
+            type: "bi.small_text_editor",
+            validationChecker: function (v) {
+                return BI.isPositiveInteger(v);
+            },
+            hgap: 4,
+            vgap: 0,
+            value: o.curr,
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: 30,
+            height: o.height - 2
+        });
+        this.pager = BI.createWidget({
+            type: "bi.pager",
+            layouts: [{
+                type: "bi.horizontal",
+                hgap: 1,
+                vgap: 1
+            }],
+
+            dynamicShow: false,
+            pages: o.pages,
+            curr: o.curr,
+            groups: 0,
+
+            first: false,
+            last: false,
+            prev: {
+                type: "bi.icon_button",
+                value: "prev",
+                title: BI.i18nText("BI-Previous_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_First_Page"),
+                height: o.height - 2,
+                cls: "number-pager-prev column-pre-page-h-font"
+            },
+            next: {
+                type: "bi.icon_button",
+                value: "next",
+                title: BI.i18nText("BI-Next_Page"),
+                warningTitle: BI.i18nText("BI-Current_Is_Last_Page"),
+                height: o.height - 2,
+                cls: "number-pager-next column-next-page-h-font"
+            },
+
+            hasPrev: o.hasPrev,
+            hasNext: o.hasNext,
+            firstPage: o.firstPage,
+            lastPage: o.lastPage
+        });
+
+        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function () {
+            self.pager.setValue(self.editor.getValue());
+        });
+        this.pager.on(BI.Pager.EVENT_CHANGE, function () {
+            if (self.getCurrentPage() !== self.pager.getCurrentPage()) {
+                self.currentPage = self.pager.getCurrentPage();
+                self.fireEvent(BI.SkipPager.EVENT_CHANGE);
+            }
+        });
+        this.pager.on(BI.Pager.EVENT_AFTER_POPULATE, function () {
+            self.editor.setValue(self.pager.getCurrentPage());
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            items: [{type: "bi.label", text: "第"}, this.editor, {type: "bi.label", text: "页"}, this.pager]
+        })
+    },
+
+    getCurrentPage: function () {
+        return this.currentPage;
+    },
+
+    setValue: function(v){
+        this.currentPage = v;
+        this.pager.setValue(v);
+    },
+
+    populate: function () {
+        this.pager.populate();
+    }
+});
+BI.SkipPager.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.skip_pager", BI.SkipPager);/**
+ * 分段控件使用的button
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.SegmentButton
+ * @extends BI.BasicButton
+ */
+BI.SegmentButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function() {
+        var conf = BI.SegmentButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            baseCls : (conf.baseCls ||"")+' bi-segment-button',
+            shadow: true,
+            readonly: true,
+            hgap: 10
+        })
+    },
+
+    _init:function() {
+        BI.SegmentButton.superclass._init.apply(this, arguments);
+        var opts = this.options, self = this;
+        //if (BI.isNumber(opts.height) && BI.isNull(opts.lineHeight)) {
+        //    this.element.css({lineHeight : (opts.height - 2) + 'px'});
+        //}
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            height: opts.height-2,
+            whiteSpace: opts.whiteSpace,
+            text: opts.text,
+            value: opts.value,
+            hgap: opts.hgap
+        })
+    },
+
+    setSelected: function(){
+        BI.SegmentButton.superclass.setSelected.apply(this, arguments);
+    },
+
+    setText : function(text) {
+        BI.SegmentButton.superclass.setText.apply(this, arguments);
+        this.text.setText(text);
+    },
+
+    destroy : function() {
+        BI.SegmentButton.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.segment_button', BI.SegmentButton);/**
+ * 单选按钮组
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.Segment
+ * @extends BI.Widget
+ */
+BI.Segment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Segment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-segment",
+            items: [],
+            height: 30
+        });
+    },
+    _init: function () {
+        BI.Segment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.buttonGroup = BI.createWidget({
+            element: this,
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.segment_button",
+                height: o.height - 2,
+                whiteSpace: o.whiteSpace
+            }),
+            layout: [
+                {
+                    type: "bi.center"
+                }
+            ]
+        })
+        this.buttonGroup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments)
+        });
+        this.buttonGroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.Segment.EVENT_CHANGE, value, obj)
+        })
+    },
+
+    setValue: function (v) {
+        this.buttonGroup.setValue(v);
+    },
+
+    setEnabledValue: function (v) {
+        this.buttonGroup.setEnabledValue(v);
+    },
+
+    setEnable: function (v) {
+        this.buttonGroup.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.buttonGroup.getValue();
+    }
+});
+BI.Segment.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.segment', BI.Segment);/**
+ *
+ * 层级树状结构的表格
+ *
+ * Created by GUY on 2016/8/12.
+ * @class BI.DynamicSummaryLayerTreeTable
+ * @extends BI.Widget
+ */
+BI.DynamicSummaryLayerTreeTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DynamicSummaryLayerTreeTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-dynamic-summary-layer-tree-table",
+            logic: { //冻结的页面布局逻辑
+                dynamic: false
+            },
+
+            isNeedResize: false,//是否需要调整列宽
+            isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效
+
+            isNeedMerge: true,//是否需要合并单元格
+            mergeCols: [],
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 25,
+            footerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: false,
+
+            header: [],
+            footer: false,
+            items: [],
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        })
+    },
+
+    _getVDeep: function () {
+        return this.options.crossHeader.length;//纵向深度
+    },
+
+    _getHDeep: function () {
+        var o = this.options;
+        return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1);
+    },
+
+    _createHeader: function (vDeep) {
+        var self = this, o = this.options;
+        var header = o.header || [], crossHeader = o.crossHeader || [];
+        var items = BI.DynamicSummaryTreeTable.formatCrossItems(o.crossItems, vDeep);
+        var result = [];
+        BI.each(items, function (row, node) {
+            var c = [crossHeader[row]];
+            result.push(c.concat(node || []));
+        });
+        var newHeader = this._formatColumns(header);
+        var deep = this._getHDeep();
+        if (deep <= 0) {
+            newHeader.unshift({
+                cls: "layer-tree-table-title",
+                text: BI.i18nText("BI-Row_Header")
+            });
+        } else {
+            newHeader[0] = {
+                cls: "layer-tree-table-title",
+                text: BI.i18nText("BI-Row_Header")
+            };
+        }
+        result.push(newHeader);
+        return result;
+    },
+
+    _formatItems: function (nodes, deep) {
+        var self = this, o = this.options;
+        var result = [];
+
+        function track(node, layer) {
+            node.type || (node.type = "bi.layer_tree_table_cell");
+            node.layer = layer;
+            var next = [node];
+            next = next.concat(node.values || []);
+            if (next.length > 0) {
+                result.push(next);
+            }
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    track(child, layer + 1);
+                });
+            }
+        }
+
+        BI.each(nodes, function (i, node) {
+            BI.each(node.children, function (j, c) {
+                track(c, 0);
+            });
+            if (BI.isArray(node.values)) {
+                var next = [{cls: "summary-cell last", text: BI.i18nText("BI-Summary_Values")}].concat(node.values);
+                result.push(next)
+            }
+        });
+        return BI.DynamicSummaryTreeTable.formatSummaryItems(result, o.crossItems, deep);
+    },
+
+    _formatCols: function (cols, deep) {
+        deep = deep || this._getHDeep();
+        cols = this._formatColumns(cols);
+        return BI.map(cols, function (i, c) {
+            return c - (deep - 1);
+        })
+    },
+
+    _formatColumns: function (columns, deep) {
+        if (BI.isNotEmptyArray(columns)) {
+            deep = deep || this._getHDeep();
+            return columns.slice(Math.max(0, deep - 1));
+        }
+        return columns;
+    },
+
+    _init: function () {
+        BI.DynamicSummaryLayerTreeTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var deep = this._getHDeep();
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(vDeep);
+        var items = this._formatItems(o.items, deep);
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            element: this,
+            logic: o.logic,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: this._formatCols(o.freezeCols, deep),
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: [],
+            mergeRule: o.mergeRule,
+            columnSize: this._formatColumns(o.columnSize, deep),
+            headerRowSize: o.headerRowSize,
+            footerRowSize: o.footerRowSize,
+            rowSize: o.rowSize,
+            regionColumnSize: o.regionColumnSize,
+            header: header,
+            footer: this._formatColumns(o.footer, deep),
+            items: items
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+    },
+
+    resize: function () {
+        this.table.resize();
+    },
+
+    setColumnSize: function (columnSize) {
+        columnSize = this._formatColumns(columnSize);
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        var columnSize = this.table.getColumnSize();
+        var deep = this._getHDeep();
+        var pre = [];
+        if (deep > 0) {
+            pre = BI.makeArray(deep - 1, 0);
+        }
+        return pre.concat(columnSize);
+    },
+
+    getCalculateColumnSize: function () {
+        var columnSize = this.table.getCalculateColumnSize();
+        var deep = this._getHDeep();
+        var pre = [];
+        if (deep > 0) {
+            pre = BI.makeArray(deep - 1, "");
+        }
+        return pre.concat(columnSize);
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        columnSize = this._formatColumns(columnSize);
+        this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize();
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize();
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    attr: function (key, value) {
+        var self = this;
+        if (BI.isObject(key)) {
+            BI.each(key, function (k, v) {
+                self.attr(k, v);
+            });
+            return;
+        }
+        BI.DynamicSummaryLayerTreeTable.superclass.attr.apply(this, arguments);
+        switch (key) {
+            case "columnSize":
+            case "footer":
+                value = this._formatColumns(value);
+                break;
+            case "freezeCols":
+                value = value.length > 0 ? [0] : [];
+                break;
+            case "mergeCols":
+                value = value.length > 0 ? [0] : [];
+                break;
+        }
+        this.table.attr.apply(this.table, [key, value]);
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        o.items = items || [];
+        if (header) {
+            o.header = header;
+        }
+        if (crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        var deep = this._getHDeep();
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(vDeep);
+        items = this._formatItems(o.items, deep);
+        this.table.populate(items, header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.DynamicSummaryLayerTreeTable.superclass.destroy.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.dynamic_summary_layer_tree_table", BI.DynamicSummaryLayerTreeTable);/**
+ *
+ * 树状结构的表格
+ *
+ * Created by GUY on 2015/8/12.
+ * @class BI.DynamicSummaryTreeTable
+ * @extends BI.Widget
+ */
+BI.DynamicSummaryTreeTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DynamicSummaryTreeTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-dynamic-summary-tree-table",
+            logic: { //冻结的页面布局逻辑
+                dynamic: false
+            },
+
+            isNeedResize: false,//是否需要调整列宽
+            isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效
+
+            isNeedMerge: true,//是否需要合并单元格
+            mergeCols: [],
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 25,
+            footerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: false,
+
+            header: [],
+            footer: false,
+            items: [],
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        })
+    },
+
+    _createHeader: function (deep, vDeep) {
+        var self = this, o = this.options;
+        var header = o.header || [], crossHeader = o.crossHeader || [];
+        var items = BI.DynamicSummaryTreeTable.formatCrossItems(o.crossItems, vDeep);
+        var result = [];
+        BI.each(items, function (row, node) {
+            var c = [];
+            for (var i = 0; i < deep; i++) {
+                c.push(crossHeader[row]);
+            }
+            result.push(c.concat(node || []));
+        });
+        result.push(header);
+        return result;
+    },
+
+    _getVDeep: function () {
+        return this.options.crossHeader.length;//纵向深度
+    },
+
+    _getHDeep: function () {
+        var o = this.options;
+        return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1);
+    },
+
+    _init: function () {
+        BI.DynamicSummaryTreeTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var deep = this._getHDeep();
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(deep, vDeep);
+        var items = BI.DynamicSummaryTreeTable.formatItems(o.items, deep);
+        items = BI.DynamicSummaryTreeTable.formatSummaryItems(items, o.crossItems, deep);
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            element: this,
+            logic: o.logic,
+
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: o.columnSize,
+            headerRowSize: o.headerRowSize,
+            footerRowSize: o.footerRowSize,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize,
+
+            header: header,
+            footer: o.footer,
+            items: items
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+    },
+
+    resize: function () {
+        this.table.resize();
+    },
+
+    setColumnSize: function (columnSize) {
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    getCalculateColumnSize: function () {
+        return this.table.getCalculateColumnSize();
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize();
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize();
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    attr: function () {
+        BI.DynamicSummaryTreeTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        o.items = items || [];
+        if (header) {
+            o.header = header;
+        }
+        if (crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        var deep = this._getHDeep();
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(deep, vDeep);
+        items = BI.DynamicSummaryTreeTable.formatItems(o.items, deep);
+        items = BI.DynamicSummaryTreeTable.formatSummaryItems(items, o.crossItems, deep);
+        this.table.populate(items, header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.DynamicSummaryTreeTable.superclass.destroy.apply(this, arguments);
+    }
+});
+
+BI.extend(BI.DynamicSummaryTreeTable, {
+    formatItems: function (nodes, deep, isCross) {
+        var self = this;
+        var result = [];
+
+        function track(store, node) {
+            var next;
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    var next;
+                    if (store != -1) {
+                        next = BI.clone(store);
+                        next.push(node);
+                    } else {
+                        next = [];
+                    }
+                    track(next, child);
+                });
+                if (store != -1) {
+                    next = BI.clone(store);
+                    next.push(node);
+                } else {
+                    next = [];
+                }
+                if ((store == -1 || node.children.length > 1) && BI.isNotEmptyArray(node.values)) {
+                    var cls = store === -1 ? " last" : "";
+                    var id = BI.UUID();
+                    for (var i = next.length; i < deep; i++) {
+                        next.push({text: BI.i18nText("BI-Summary_Values"), tag: id, cls: "summary-cell" + cls});
+                    }
+                    if (!isCross) {
+                        next = next.concat(node.values);
+                    }
+                    if (next.length > 0) {
+                        if (!isCross) {
+                            result.push(next);
+                        } else {
+                            for (var k = 0, l = node.values.length; k < l; k++) {
+                                result.push(next);
+                            }
+                        }
+                    }
+                }
+                return;
+            }
+            if (store != -1) {
+                next = BI.clone(store);
+                for (var i = next.length; i < deep; i++) {
+                    next.push(node);
+                }
+            } else {
+                next = [];
+            }
+            if (!isCross && BI.isArray(node.values)) {
+                next = next.concat(node.values);
+            }
+            if (isCross && BI.isArray(node.values)) {
+                for (var i = 0, len = node.values.length; i < len - 1; i++) {
+                    if (next.length > 0) {
+                        result.push(next);
+                    }
+                }
+            }
+            if (next.length > 0) {
+                result.push(next);
+            }
+        }
+
+        BI.each(nodes, function (i, node) {
+            track(-1, node);
+        });
+        //填充空位
+        BI.each(result, function (i, line) {
+            var last = BI.last(line);
+            for (var i = line.length; i < deep; i++) {
+                line.push(last);
+            }
+        });
+        return result;
+    },
+
+    formatCrossItems: function (nodes, deep) {
+        var items = BI.DynamicSummaryTreeTable.formatItems(nodes, deep, true);
+        return BI.unzip(items);
+    },
+
+    formatSummaryItems: function (items, crossItems, deep) {
+        //求纵向需要去除的列
+        var cols = [];
+        var leaf = 0;
+
+        function track(node) {
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    track(child);
+                });
+                if (BI.isNotEmptyArray(node.values)) {
+                    leaf++;
+                    if (node.children.length === 1) {
+                        cols.push(leaf - 1 + deep);
+                    }
+                }
+                return;
+            }
+            leaf++;
+        }
+
+        BI.each(crossItems, function (i, node) {
+            track(node);
+        });
+
+        if (cols.length > 0) {
+            BI.each(items, function (i, node) {
+                BI.removeAt(node, cols);
+            })
+        }
+        return items;
+    }
+});
+
+$.shortcut("bi.dynamic_summary_tree_table", BI.DynamicSummaryTreeTable);/**
+ * Created by GUY on 2016/5/7.
+ * @class BI.LayerTreeTableCell
+ * @extends BI.Single
+ */
+BI.LayerTreeTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LayerTreeTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-layer-tree-table-cell",
+            layer: 0,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.LayerTreeTableCell.superclass._init.apply(this, arguments);
+        var o = this.options;
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            height: o.height,
+            text: o.text,
+            value: o.value,
+            lgap: 5 + 30 * o.layer,
+            rgap: 5
+        })
+    }
+});
+
+$.shortcut("bi.layer_tree_table_cell", BI.LayerTreeTableCell);/**
+ *
+ * 层级树状结构的表格
+ *
+ * Created by GUY on 2016/5/7.
+ * @class BI.LayerTreeTable
+ * @extends BI.Widget
+ */
+BI.LayerTreeTable = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LayerTreeTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-layer-tree-table",
+            logic: { //冻结的页面布局逻辑
+                dynamic: false
+            },
+
+            isNeedResize: false,//是否需要调整列宽
+            isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效
+
+            isNeedMerge: true,//是否需要合并单元格
+            mergeCols: [],
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 25,
+            footerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: false,
+
+            header: [],
+            footer: false,
+            items: [],
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        })
+    },
+
+    _getVDeep: function () {
+        return this.options.crossHeader.length;//纵向深度
+    },
+
+    _getHDeep: function () {
+        var o = this.options;
+        return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1);
+    },
+
+    _createHeader: function (vDeep) {
+        var self = this, o = this.options;
+        var header = o.header || [], crossHeader = o.crossHeader || [];
+        var items = BI.TableTree.formatCrossItems(o.crossItems, vDeep);
+        var result = [];
+        BI.each(items, function (row, node) {
+            var c = [crossHeader[row]];
+            result.push(c.concat(node || []));
+        });
+        var newHeader = this._formatColumns(header);
+        var deep = this._getHDeep();
+        if (deep <= 0) {
+            newHeader.unshift({
+                cls: "layer-tree-table-title",
+                text: BI.i18nText("BI-Row_Header")
+            });
+        } else {
+            newHeader[0] = {
+                cls: "layer-tree-table-title",
+                text: BI.i18nText("BI-Row_Header")
+            };
+        }
+        result.push(newHeader);
+        return result;
+    },
+
+    _formatItems: function (nodes) {
+        var self = this;
+        var result = [];
+
+        function track(node, layer) {
+            node.type || (node.type = "bi.layer_tree_table_cell");
+            node.layer = layer;
+            var next = [node];
+            next = next.concat(node.values || []);
+            if (next.length > 0) {
+                result.push(next);
+            }
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    track(child, layer + 1);
+                });
+            }
+        }
+
+        BI.each(nodes, function (i, node) {
+            BI.each(node.children, function (j, c) {
+                track(c, 0);
+            });
+            if (BI.isArray(node.values)) {
+                var next = [{cls: "summary-cell last", text: BI.i18nText("BI-Summary_Values")}].concat(node.values);
+                result.push(next)
+            }
+        });
+        return result;
+    },
+
+    _formatCols: function (cols, deep) {
+        deep = deep || this._getHDeep();
+        cols = this._formatColumns(cols);
+        return BI.map(cols, function (i, c) {
+            return c - (deep - 1);
+        })
+    },
+
+    _formatColumns: function (columns, deep) {
+        if (BI.isNotEmptyArray(columns)) {
+            deep = deep || this._getHDeep();
+            return columns.slice(Math.max(0, deep - 1));
+        }
+        return columns;
+    },
+
+    _init: function () {
+        BI.LayerTreeTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var deep = this._getHDeep();
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(vDeep);
+        var items = this._formatItems(o.items);
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            element: this,
+            logic: o.logic,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: this._formatCols(o.freezeCols, deep),
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: [],
+            mergeRule: o.mergeRule,
+            columnSize: this._formatColumns(o.columnSize, deep),
+            headerRowSize: o.headerRowSize,
+            footerRowSize: o.footerRowSize,
+            rowSize: o.rowSize,
+            regionColumnSize: o.regionColumnSize,
+            header: header,
+            footer: this._formatColumns(o.footer, deep),
+            items: items
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_COLUMN_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+    },
+
+    resize: function () {
+        this.table.resize();
+    },
+
+    setColumnSize: function (columnSize) {
+        columnSize = this._formatColumns(columnSize);
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        var columnSize = this.table.getColumnSize();
+        var deep = this._getHDeep();
+        var pre = [];
+        if (deep > 0) {
+            pre = BI.makeArray(deep - 1, 0);
+        }
+        return pre.concat(columnSize);
+    },
+
+    getCalculateColumnSize: function () {
+        var columnSize = this.table.getCalculateColumnSize();
+        var deep = this._getHDeep();
+        var pre = [];
+        if (deep > 0) {
+            pre = BI.makeArray(deep - 1, "");
+        }
+        return pre.concat(columnSize);
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        columnSize = this._formatColumns(columnSize);
+        this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize();
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize();
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    attr: function (key, value) {
+        var self = this;
+        if (BI.isObject(key)) {
+            BI.each(key, function (k, v) {
+                self.attr(k, v);
+            });
+            return;
+        }
+        BI.LayerTreeTable.superclass.attr.apply(this, arguments);
+        switch (key) {
+            case "columnSize":
+            case "footer":
+                value = this._formatColumns(value);
+                break;
+            case "freezeCols":
+                value = value.length > 0 ? [0] : [];
+                break;
+            case "mergeCols":
+                value = value.length > 0 ? [0] : [];
+                break;
+        }
+        this.table.attr.apply(this.table, [key, value]);
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        o.items = items || [];
+        if (header) {
+            o.header = header;
+        }
+        if (crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        var vDeep = this._getVDeep();
+        var header = this._createHeader(vDeep);
+        items = this._formatItems(o.items);
+        this.table.populate(items, header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.LayerTreeTable.superclass.destroy.apply(this, arguments);
+    }
+});
+
+$.shortcut("bi.layer_tree_table", BI.LayerTreeTable);/**
+ * 分页table
+ *
+ * Created by GUY on 2015/9/8.
+ * @class BI.Tabler
+ * @extends BI.Widget
+ */
+BI.Tabler = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Tabler.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-tabler",
+
+            pager: {},
+
+            layouts: [{
+                type: "bi.float_center_adapt"
+            }],
+
+            tabler: {
+                isNeedFreeze: false,//是否需要冻结单元格
+                freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效
+
+                isNeedMerge: true,//是否需要合并单元格
+
+                mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                    return BI.isEqual(row1, row2);
+                },
+
+                columnSize: [],
+                rowSize: 37,
+                header: [],
+                items: [],
+
+                //交叉表头
+                crossHeader: [],
+                crossItems: []
+            }
+        })
+    },
+    _init: function () {
+        BI.Tabler.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.pager = BI.createWidget(o.pager, {
+            type: "bi.pager"
+        });
+        var creater = BI.createWidget({
+            type: "bi.button_tree",
+            items: [{
+                el: this.pager
+            }],
+            layouts: o.layouts
+        })
+        this.pager.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.Tabler.EVENT_CHANGE);
+            }
+        });
+        this.container = BI.createWidget({
+            type: "bi.layout"
+        })
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.container
+            }, {
+                el: creater,
+                height: 40
+            }]
+        });
+        this.populate();
+    },
+
+    getCurrentPage: function () {
+        return this.pager.getValue();
+    },
+
+    populate: function (opt) {
+        var o = this.options;
+        this.container.empty();
+
+        BI.extend(o.tabler, opt);
+        this.table = BI.createWidget(this.options.tabler, {
+            type: "bi.table_tree",
+            element: this.container
+        });
+    }
+});
+BI.Tabler.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.tabler", BI.Tabler);/**
+ * guy
+ * 气泡提示
+ * @class BI.Bubble
+ * @extends BI.Tip
+ * @type {*|void|Object}
+ */
+BI.Bubble = BI.inherit(BI.Tip, {
+    _defaultConfig: function() {
+        return BI.extend(BI.Bubble.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-bubble",
+            direction: "top",
+            text: "",
+            height: 35
+        })
+    },
+    _init : function() {
+        BI.Bubble.superclass._init.apply(this, arguments);
+        var fn = function (e) {
+            e.stopPropagation();
+            e.stopEvent();
+            return false;
+        };
+        this.element.bind({"click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn});
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this["_" + this.options.direction]()]
+        })
+    },
+
+    _createBubbleText: function(){
+        return (this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "bubble-text",
+            text: this.options.text,
+            hgap: 10,
+            height: 30
+        }));
+    },
+
+    _top: function(){
+        return BI.createWidget({
+            type: "bi.vertical",
+            items: [{
+                el: this._createBubbleText(),
+                height: 30
+            }, {
+                el: {
+                    type: "bi.layout"
+                },
+                height: 3
+            }]
+        })
+    },
+
+    _bottom: function(){
+        return BI.createWidget({
+            type: "bi.vertical",
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                height: 3
+            }, {
+                el: this._createBubbleText(),
+                height: 30
+            }]
+        })
+    },
+
+    _left: function(){
+        return BI.createWidget({
+            type: "bi.right",
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    width: 3,
+                    height: 30
+                }
+            }, {
+                el: this._createBubbleText()
+            }]
+        })
+    },
+
+    _right: function(){
+        return BI.createWidget({
+            type: "bi.inline",
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    width: 3,
+                    height: 30
+                }
+            }, {
+                el: this._createBubbleText()
+            }]
+        })
+    },
+
+    setText: function(text){
+        this.text.setText(text);
+    }
+});
+
+$.shortcut("bi.bubble", BI.Bubble);/**
+ * toast提示
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.Toast
+ * @extends BI.Tip
+ */
+BI.Toast = BI.inherit(BI.Tip, {
+    _const: {
+        minWidth: 200,
+        hgap: 20
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Toast.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-toast",
+            text: "",
+            level: "success",//success或warning
+            height: 30
+        })
+    },
+    _init: function () {
+        BI.Toast.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.element.css({
+            minWidth: this._const.minWidth + "px"
+        })
+        this.element.addClass("toast-" + o.level);
+        var fn = function (e) {
+            e.stopPropagation();
+            e.stopEvent();
+            return false;
+        };
+        this.element.bind({"click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn});
+
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            text: o.text,
+            height: 30,
+            hgap: this._const.hgap
+        })
+    },
+
+    setWidth: function(width){
+        this.element.width(width);
+    },
+
+    setText: function (text) {
+        this.text.setText(text);
+    }
+});
+
+$.shortcut("bi.toast", BI.Toast);/**
+ * toast提示
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.Tooltip
+ * @extends BI.Tip
+ */
+BI.Tooltip = BI.inherit(BI.Tip, {
+    _const: {
+        hgap: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Tooltip.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-tooltip",
+            text: "",
+            level: "success",//success或warning
+            height: 20
+        })
+    },
+    _init: function () {
+        BI.Tooltip.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.element.addClass("tooltip-" + o.level);
+        var fn = function (e) {
+            e.stopPropagation();
+            e.stopEvent();
+            return false;
+        };
+        this.element.bind({"click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn});
+
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            text: o.text,
+            textHeight: 20,
+            hgap: this._const.hgap
+        });
+    },
+
+    setWidth: function(width){
+        this.element.width(width - 2 * this._const.hgap);
+    },
+
+    setText: function (text) {
+        this.text.setText(text);
+    },
+
+    setLevel: function (level) {
+       this.element.removeClass("tooltip-success").removeClass("tooltip-warning");
+        this.element.addClass("tooltip-" + level);
+    }
+});
+
+$.shortcut("bi.tooltip", BI.Tooltip);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/8/25.
+ * @class BI.MultiSelectBar
+ * @extends BI.BasicButton
+ */
+BI.MultiSelectBar = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multi-select-bar",
+            height: 25,
+            text: BI.i18nText('BI-Select_All'),
+            isAllCheckedBySelectedValue: BI.emptyFn,
+            onCheck: BI.emptyFn,
+            isHalfCheckedBySelectedValue: function (selectedValues) {
+                return selectedValues.length > 0;
+            }
+        })
+    },
+    _init: function () {
+        BI.MultiSelectBar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.checkbox",
+            stopPropagation: true,
+            handler: function () {
+                self.setSelected(self.isSelected());
+                o.onCheck.call(self, self.isSelected());
+            }
+        });
+        this.half = BI.createWidget({
+            type: "bi.half_icon_button",
+            stopPropagation: true,
+            handler: function () {
+                self.setSelected(true);
+                o.onCheck.call(self, self.isSelected());
+            }
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.isSelected(), self);
+        });
+        this.half.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.isSelected(), self);
+        });
+        this.half.on(BI.HalfIconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectBar.EVENT_CHANGE, self.isSelected(), self);
+        });
+        this.checkbox.on(BI.Checkbox.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectBar.EVENT_CHANGE, self.isSelected(), self);
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            keyword: o.keyword,
+            value: o.value,
+            py: o.py
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                width: 36,
+                el: {
+                    type: "bi.center_adapt",
+                    items: [this.checkbox, this.half]
+                }
+            }, {
+                el: this.text
+            }]
+        });
+        this.half.invisible();
+    },
+
+    doClick: function () {
+        var isHalf = this.isHalfSelected(), isSelected = this.isSelected();
+        if (isHalf === true) {
+            this.setSelected(true);
+        } else {
+            this.setSelected(!isSelected);
+        }
+
+        if (this.isValid()) {
+            this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, this.getValue(), this);
+            this.options.onCheck.call(this, this.isSelected());
+            this.fireEvent(BI.MultiSelectBar.EVENT_CHANGE, this.isSelected(), this);
+        }
+    },
+
+    setSelected: function (v) {
+        this.checkbox.setSelected(v);
+        this.setHalfSelected(false);
+    },
+
+    setHalfSelected: function (b) {
+        this._half = !!b;
+        if (b === true) {
+            this.half.visible();
+            this.checkbox.invisible();
+        } else {
+            this.half.invisible();
+            this.checkbox.visible();
+        }
+    },
+
+    isHalfSelected: function () {
+        return !!this._half;
+    },
+
+    isSelected: function () {
+        return this.checkbox.isSelected();
+    },
+
+    setValue: function (selectedValues) {
+        BI.MultiSelectBar.superclass.setValue.apply(this, arguments);
+        var isAllChecked = this.options.isAllCheckedBySelectedValue.apply(this, arguments);
+        this.setSelected(isAllChecked);
+        !isAllChecked && this.setHalfSelected(this.options.isHalfCheckedBySelectedValue.apply(this, arguments));
+    },
+
+    setEnable: function (b) {
+        BI.MultiSelectBar.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+        this.half.setEnable(b);
+        this.text.setEnable(b);
+    }
+});
+BI.MultiSelectBar.EVENT_CHANGE = "MultiSelectBar.EVENT_CHANGE";
+$.shortcut("bi.multi_select_bar", BI.MultiSelectBar);/**
+ * @class BI.HandStandBranchTree
+ * @extends BI.Widget
+ * create by young
+ * 横向分支的树
+ */
+BI.HandStandBranchTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.HandStandBranchTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-handstand-branch-tree",
+            expander: {},
+            el: {},
+            items: []
+        })
+    },
+    _init: function () {
+        BI.HandStandBranchTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.branchTree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.handstand_branch_expander",
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            }, o.expander),
+            el: BI.extend({
+                type: "bi.button_tree",
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                layouts: [{
+                    type: "bi.horizontal_adapt"
+                }]
+            }, o.el),
+            items: this.options.items
+        });
+        this.branchTree.on(BI.CustomTree.EVENT_CHANGE, function(){
+            self.fireEvent(BI.HandStandBranchTree.EVENT_CHANGE, arguments);
+        });
+        this.branchTree.on(BI.Controller.EVENT_CHANGE, function(){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    populate: function () {
+        this.branchTree.populate.apply(this.branchTree, arguments);
+    },
+
+    getValue: function () {
+        return this.branchTree.getValue();
+    }
+});
+BI.HandStandBranchTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.handstand_branch_tree", BI.HandStandBranchTree);/**
+ * @class BI.BranchTree
+ * @extends BI.Widget
+ * create by young
+ * 横向分支的树
+ */
+BI.BranchTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BranchTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-branch-tree",
+            expander: {},
+            el: {},
+            items: []
+        })
+    },
+    _init: function () {
+        BI.BranchTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.branchTree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.branch_expander",
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            }, o.expander),
+            el: BI.extend({
+                type: "bi.button_tree",
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }, o.el),
+            items: this.options.items
+        });
+        this.branchTree.on(BI.CustomTree.EVENT_CHANGE, function(){
+            self.fireEvent(BI.BranchTree.EVENT_CHANGE, arguments);
+        });
+        this.branchTree.on(BI.Controller.EVENT_CHANGE, function(){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    populate: function () {
+        this.branchTree.populate.apply(this.branchTree, arguments);
+    },
+
+    getValue: function () {
+        return this.branchTree.getValue();
+    }
+});
+BI.BranchTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.branch_tree", BI.BranchTree);/**
+ * guy
+ * 异步树
+ * @class BI.DisplayTree
+ * @extends BI.TreeView
+ */
+BI.DisplayTree = BI.inherit(BI.TreeView, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DisplayTree.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-display-tree"
+        })
+    },
+    _init: function () {
+        BI.DisplayTree.superclass._init.apply(this, arguments);
+    },
+
+    //配置属性
+    _configSetting: function () {
+        var setting = {
+            view: {
+                selectedMulti: false,
+                dblClickExpand: false,
+                showIcon: false,
+                showTitle: false
+            },
+            data: {
+                key: {
+                    title: "title",
+                    name: "text"
+                },
+                simpleData: {
+                    enable: true
+                }
+            },
+            callback: {
+                beforeCollapse: beforeCollapse
+            }
+        };
+
+        function beforeCollapse(treeId, treeNode) {
+            return false;
+        }
+
+        return setting;
+    },
+
+    initTree: function (nodes, setting) {
+        var setting = setting || this._configSetting();
+        this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes);
+    },
+
+    destroy: function () {
+        BI.DisplayTree.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.display_tree", BI.DisplayTree);/**
+ * guy
+ * 二级树
+ * @class BI.LevelTree
+ * @extends BI.Single
+ */
+BI.LevelTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LevelTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-level-tree",
+            el: {
+                chooseType: 0
+            },
+            expander: {},
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.LevelTree.superclass._init.apply(this, arguments);
+
+        this.initTree(this.options.items);
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {layer: layer};
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+                self._formatItems(node.children, layer + 1);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _assertId: function (sNodes) {
+        BI.each(sNodes, function (i, node) {
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.empty();
+        this._assertId(nodes);
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            }, o.expander),
+
+            items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0),
+
+            el: BI.extend({
+                type: "bi.button_tree",
+                chooseType: 0,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }, o.el)
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.LevelTree.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+
+    //生成树方法
+    stroke: function (nodes) {
+        this.tree.stroke.apply(this.tree, arguments);
+    },
+
+    populate: function (items) {
+        items = this._formatItems(BI.Tree.transformToTreeFormat(items), 0);
+        this.tree.populate(items);
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    getAllLeaves: function () {
+        return this.tree.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree.getNodeByValue(id);
+    }
+});
+BI.LevelTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.level_tree", BI.LevelTree);/**
+ * 简单的多选树
+ *
+ * Created by GUY on 2016/2/16.
+ * @class BI.SimpleTreeView
+ * @extends BI.Widget
+ */
+BI.SimpleTreeView = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleTreeView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-simple-tree",
+            itemsCreator: BI.emptyFn,
+            items: null
+        })
+    },
+    _init: function () {
+        BI.SimpleTreeView.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.structure = new BI.Tree();
+        this.tree = BI.createWidget({
+            type: "bi.tree",
+            element: this,
+            itemsCreator: function (op, callback) {
+                var fn = function (items) {
+                    callback({
+                        items: items
+                    });
+                    self.structure.initTree(BI.Tree.transformToTreeFormat(items));
+                };
+                if (BI.isNotNull(o.items)) {
+                    fn(o.items);
+                } else {
+                    o.itemsCreator(op, fn);
+                }
+            }
+        });
+        this.tree.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleTreeView.EVENT_CHANGE, arguments);
+        });
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate();
+        }
+    },
+
+    populate: function (items, keyword) {
+        if (items) {
+            this.options.items = items;
+        }
+        this.tree.stroke({
+            keyword: keyword
+        });
+    },
+
+    setValue: function (v) {
+        v || (v = []);
+        var self = this, map = {};
+        var selected = [];
+        BI.each(v, function (i, val) {
+            var node = self.structure.search(val, "value");
+            if (node) {
+                var p = node;
+                p = p.getParent();
+                if (p) {
+                    if (!map[p.value]) {
+                        map[p.value] = 0;
+                    }
+                    map[p.value]++;
+                }
+
+                while (p && p.getChildrenLength() <= map[p.value]) {
+                    selected.push(p.value);
+                    p = p.getParent();
+                    if (p) {
+                        if (!map[p.value]) {
+                            map[p.value] = 0;
+                        }
+                        map[p.value]++;
+                    }
+                }
+            }
+        });
+
+        this.tree.setValue(BI.makeObject(v.concat(selected)));
+    },
+
+    _getValue: function () {
+        var self = this, result = [], val = this.tree.getValue();
+        var track = function (nodes) {
+            BI.each(nodes, function (key, node) {
+                if (BI.isEmpty(node)) {
+                    result.push(key);
+                } else {
+                    track(node);
+                }
+            })
+        };
+        track(val);
+        return result;
+    },
+
+    empty: function () {
+        this.tree.empty();
+    },
+
+    getValue: function () {
+        var self = this, result = [], val = this._getValue();
+        BI.each(val, function (i, key) {
+            var target = self.structure.search(key, "value");
+            if (target) {
+                self.structure._traverse(target, function (node) {
+                    if (node.isLeaf()) {
+                        result.push(node.value);
+                    }
+                })
+            }
+        });
+        return result;
+    }
+});
+BI.SimpleTreeView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.simple_tree", BI.SimpleTreeView);
+/**
+ * 文本输入框trigger
+ *
+ * Created by GUY on 2015/9/15.
+ * @class BI.EditorTrigger
+ * @extends BI.Trigger
+ */
+BI.EditorTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.EditorTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-editor-trigger",
+            height: 30,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            allowBlank: false,
+            watermark: "",
+            errorText: "",
+            triggerWidth: 30
+        });
+    },
+
+    _init: function () {
+        this.options.height -= 2;
+        BI.EditorTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: false,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.EditorTrigger.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: o.triggerWidth
+                    },
+                    width: o.triggerWidth
+                }
+            ]
+        });
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    setValue: function (value) {
+        this.editor.setValue(value);
+    },
+
+    setText: function (text) {
+        this.editor.setState(text);
+    }
+});
+BI.EditorTrigger.EVENT_CHANGE = "BI.EditorTrigger.EVENT_CHANGE";
+$.shortcut("bi.editor_trigger", BI.EditorTrigger);/**
+ * 图标按钮trigger
+ *
+ * Created by GUY on 2015/10/8.
+ * @class BI.IconTrigger
+ * @extends BI.Trigger
+ */
+BI.IconTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.IconTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-icon-trigger",
+            el: {},
+            height: 30
+        });
+    },
+    _init: function () {
+        var o = this.options;
+        BI.IconTrigger.superclass._init.apply(this, arguments);
+        this.iconButton = BI.createWidget(o.el, {
+            type: "bi.trigger_icon_button",
+            element: this,
+            width: o.width,
+            height: o.height
+        });
+    }
+});
+$.shortcut('bi.icon_trigger', BI.IconTrigger);/**
+ * 文字trigger
+ *
+ * Created by GUY on 2015/9/15.
+ * @class BI.TextTrigger
+ * @extends BI.Trigger
+ */
+BI.TextTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        triggerWidth: 30
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.TextTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-trigger",
+            height: 30
+        });
+    },
+
+    _init: function () {
+        BI.TextTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            height: o.height,
+            text: o.text,
+            hgap: c.hgap
+        });
+        this.trigerButton = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: c.triggerWidth
+        });
+
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.text
+                }, {
+                    el: this.trigerButton,
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+
+    setEnable: function (v) {
+        BI.TextTrigger.superclass.setEnable.apply(this, arguments);
+        this.trigerButton.setEnable(v);
+        this.text.setEnable(v);
+    },
+
+    setValue: function (value) {
+        this.text.setValue(value);
+    },
+
+    setText: function (text) {
+        this.text.setText(text);
+    }
+});
+$.shortcut("bi.text_trigger", BI.TextTrigger);/**
+ * 选择字段trigger
+ *
+ * Created by GUY on 2015/9/15.
+ * @class BI.SelectTextTrigger
+ * @extends BI.Trigger
+ */
+BI.SelectTextTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTextTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-text-trigger",
+            height: 24
+        });
+    },
+
+    _init: function () {
+        this.options.height -= 2;
+        BI.SelectTextTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            element: this,
+            height: o.height
+        });
+        if (BI.isKey(o.text)) {
+            this.setValue(o.text);
+        }
+    },
+
+    setValue: function (vals) {
+        var o = this.options;
+        vals = BI.isArray(vals) ? vals : [vals];
+        var result = [];
+        var items = BI.Tree.transformToArrayFormat(this.options.items);
+        BI.each(items, function (i, item) {
+            if (BI.deepContains(vals, item.value)) {
+                result.push(item.text || item.value);
+            }
+        });
+
+        if (result.length > 0) {
+            this.trigger.element.removeClass("bi-water-mark");
+            this.trigger.setText(result.join(","));
+        } else {
+            this.trigger.element.addClass("bi-water-mark");
+            this.trigger.setText(o.text);
+        }
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+    }
+});
+$.shortcut("bi.select_text_trigger", BI.SelectTextTrigger);/**
+ * 选择字段trigger小一号的
+ *
+ * @class BI.SmallSelectTextTrigger
+ * @extends BI.Trigger
+ */
+BI.SmallSelectTextTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SmallSelectTextTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-small-select-text-trigger",
+            height: 20
+        });
+    },
+
+    _init: function () {
+        this.options.height -= 2;
+        BI.SmallSelectTextTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.small_text_trigger",
+            element: this,
+            height: o.height - 2
+        });
+        if (BI.isKey(o.text)) {
+            this.setValue(o.text);
+        }
+    },
+
+    setValue: function (vals) {
+        var o = this.options;
+        vals = BI.isArray(vals) ? vals : [vals];
+        var result = [];
+        var items = BI.Tree.transformToArrayFormat(this.options.items);
+        BI.each(items, function (i, item) {
+            if (BI.deepContains(vals, item.value)) {
+                result.push(item.text || item.value);
+            }
+        });
+
+        if (result.length > 0) {
+            this.trigger.element.removeClass("bi-water-mark");
+            this.trigger.setText(result.join(","));
+        } else {
+            this.trigger.element.addClass("bi-water-mark");
+            this.trigger.setText(o.text);
+        }
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+    }
+});
+$.shortcut("bi.small_select_text_trigger", BI.SmallSelectTextTrigger);/**
+ * 文字trigger(右边小三角小一号的) ==
+ *
+ * @class BI.SmallTextTrigger
+ * @extends BI.Trigger
+ */
+BI.SmallTextTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        triggerWidth: 20
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.SmallTextTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-trigger",
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.SmallTextTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            height: o.height,
+            text: o.text,
+            hgap: c.hgap
+        });
+        this.trigerButton = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: c.triggerWidth
+        });
+
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.text
+                }, {
+                    el: this.trigerButton,
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+
+    setEnable: function (v) {
+        BI.SmallTextTrigger.superclass.setEnable.apply(this, arguments);
+        this.trigerButton.setEnable(v);
+        this.text.setEnable(v);
+    },
+
+    setValue: function (value) {
+        this.text.setValue(value);
+    },
+
+    setText: function (text) {
+        this.text.setText(text);
+    }
+});
+$.shortcut("bi.small_text_trigger", BI.SmallTextTrigger);
\ No newline at end of file
diff --git a/dist/core.css b/dist/core.css
new file mode 100644
index 000000000..485d2d341
--- /dev/null
+++ b/dist/core.css
@@ -0,0 +1,9924 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+@font-face {
+  font-family: 'bi';
+  src: url('font/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('font/iconfont.woff') format('woff'), /* chrome、firefox */ url('font/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('font/iconfont.svg#svgFontName') format('svg');
+  
+  /*  iOS 4.1- */
+}
+.b-font {
+  font-family: "bi";
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: 0.2px;
+  -moz-osx-font-smoothing: grayscale;
+}
+html,
+button,
+input,
+select,
+textarea,
+* {
+  font-family: "Microsoft YaHei", "Hiragino Sans GB W3";
+}
+html,
+body,
+div,
+ul,
+li,
+img,
+a,
+span,
+p,
+* {
+  margin: 0px;
+}
+html {
+  height: 100%;
+  overflow: hidden;
+}
+body {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  top: 0;
+  left: 0;
+  background-repeat: repeat;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+  color: #1a1a1a;
+  font: normal 12px "Microsoft YaHei", "Hiragino Sans GB W3";
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-decoration: none;
+  -kthml-user-focus: normal;
+  -moz-user-focus: normal;
+  -moz-outline: 0 none;
+  outline: 0 none;
+}
+#wrapper {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  overflow: hidden;
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+a {
+  outline: none;
+  text-decoration: none;
+}
+a:focus {
+  outline: 0;
+}
+input,
+textarea {
+  margin: 0;
+  padding: 0;
+  outline: none;
+  border: 1px solid #cccccc;
+}
+ul,
+ol {
+  margin: 0;
+  padding: 0;
+}
+ul {
+  list-style: disc;
+}
+li {
+  list-style-type: none;
+}
+i {
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: 0.2px;
+  -moz-osx-font-smoothing: grayscale;
+}
+div::-webkit-scrollbar,
+textarea::-webkit-scrollbar {
+  -webkit-appearance: none;
+  background-color: #f4f4f4;
+  width: 6px;
+  height: 6px;
+}
+div::-webkit-scrollbar-thumb,
+textarea::-webkit-scrollbar-thumb {
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+  background-color: #e2e2e2;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/************hing light*****************/
+.bi-flex-center-layout {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: center;
+  /* 12版 */
+  -webkit-justify-content: center;
+  -moz-justify-content: center;
+  -ms-justify-content: center;
+  -o-justify-content: center;
+  justify-content: center;
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+}
+.bi-flex-horizontal-layout {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: flex-start;
+  /* 12版 */
+  -webkit-justify-content: flex-start;
+  -moz-justify-content: flex-start;
+  -ms-justify-content: flex-start;
+  -o-justify-content: flex-start;
+  justify-content: flex-start;
+  /* 09版 */
+  -webkit-box-align: flex-start;
+  /* 12版 */
+  -webkit-align-items: flex-start;
+  -moz-align-items: flex-start;
+  -ms-align-items: flex-start;
+  -o-align-items: flex-start;
+  align-items: flex-start;
+  /* 09版 */
+  /*-webkit-box-lines: multiple;*/
+  /* 12版 */
+  -webkit-flex-wrap: nowrap;
+  -moz-flex-wrap: nowrap;
+  -ms-flex-wrap: nowrap;
+  -o-flex-wrap: nowrap;
+  flex-wrap: nowrap;
+}
+.bi-flex-horizontal-layout.middle {
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+}
+.bi-flex-horizontal-layout.bottom {
+  /* 09版 */
+  -webkit-box-align: flex-end;
+  /* 12版 */
+  -webkit-align-items: flex-end;
+  -moz-align-items: flex-end;
+  -ms-align-items: flex-end;
+  -o-align-items: flex-end;
+  align-items: flex-end;
+}
+.bi-flex-vertical-center {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: flex-start;
+  /* 12版 */
+  -webkit-justify-content: flex-start;
+  -moz-justify-content: flex-start;
+  -ms-justify-content: flex-start;
+  -o-justify-content: flex-start;
+  justify-content: flex-start;
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+  /* 09版 */
+  /*-webkit-box-lines: multiple;*/
+  /* 12版 */
+  -webkit-flex-wrap: nowrap;
+  -moz-flex-wrap: nowrap;
+  -ms-flex-wrap: nowrap;
+  -o-flex-wrap: nowrap;
+  flex-wrap: nowrap;
+}
+.bi-flex-wrapper-center-layout .flex-wrapper-center-layout-wrapper {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: center;
+  /* 12版 */
+  -webkit-justify-content: center;
+  -moz-justify-content: center;
+  -ms-justify-content: center;
+  -o-justify-content: center;
+  justify-content: center;
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+  min-width: 100%;
+  min-height: 100%;
+  float: left;
+}
+.bi-flex-wrapper-horizontal-layout .flex-wrapper-horizontal-layout-wrapper {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: flex-start;
+  /* 12版 */
+  -webkit-justify-content: flex-start;
+  -moz-justify-content: flex-start;
+  -ms-justify-content: flex-start;
+  -o-justify-content: flex-start;
+  justify-content: flex-start;
+  /* 09版 */
+  -webkit-box-align: flex-start;
+  /* 12版 */
+  -webkit-align-items: flex-start;
+  -moz-align-items: flex-start;
+  -ms-align-items: flex-start;
+  -o-align-items: flex-start;
+  align-items: flex-start;
+  /* 09版 */
+  /*-webkit-box-lines: multiple;*/
+  /* 12版 */
+  -webkit-flex-wrap: nowrap;
+  -moz-flex-wrap: nowrap;
+  -ms-flex-wrap: nowrap;
+  -o-flex-wrap: nowrap;
+  flex-wrap: nowrap;
+  min-height: 100%;
+}
+.bi-flex-wrapper-horizontal-layout .flex-wrapper-horizontal-layout-wrapper.middle {
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+}
+.bi-flex-wrapper-horizontal-layout .flex-wrapper-horizontal-layout-wrapper.bottom {
+  /* 09版 */
+  -webkit-box-align: flex-end;
+  /* 12版 */
+  -webkit-align-items: flex-end;
+  -moz-align-items: flex-end;
+  -ms-align-items: flex-end;
+  -o-align-items: flex-end;
+  align-items: flex-end;
+}
+.bi-flex-wrapper-vertical-center .flex-wrapper-vertical-center-wrapper {
+  display: box;
+  /* OLD - Android 4.4- */
+  display: -webkit-box;
+  /* OLD - iOS 6-, Safari 3.1-6 */
+  display: -moz-box;
+  /* OLD - Firefox 19- (buggy but mostly works) */
+  display: -ms-flexbox;
+  /* TWEENER - IE 10 */
+  display: -webkit-flex;
+  /* NEW - Chrome */
+  display: flex;
+  /* NEW, Spec - Opera 12.1, Firefox 20+ */
+  /* 09版 */
+  -webkit-box-orient: horizontal;
+  /* 12版 */
+  -webkit-flex-direction: row;
+  -moz-flex-direction: row;
+  -ms-flex-direction: row;
+  -o-flex-direction: row;
+  flex-direction: row;
+  /* 09版 */
+  -webkit-box-pack: flex-start;
+  /* 12版 */
+  -webkit-justify-content: flex-start;
+  -moz-justify-content: flex-start;
+  -ms-justify-content: flex-start;
+  -o-justify-content: flex-start;
+  justify-content: flex-start;
+  /* 09版 */
+  -webkit-box-align: center;
+  /* 12版 */
+  -webkit-align-items: center;
+  -moz-align-items: center;
+  -ms-align-items: center;
+  -o-align-items: center;
+  align-items: center;
+  /* 09版 */
+  /*-webkit-box-lines: multiple;*/
+  /* 12版 */
+  -webkit-flex-wrap: nowrap;
+  -moz-flex-wrap: nowrap;
+  -ms-flex-wrap: nowrap;
+  -o-flex-wrap: nowrap;
+  flex-wrap: nowrap;
+  min-height: 100%;
+  float: left;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-inline-center-adapt-layout:after {
+  display: inline-block;
+  width: 0;
+  min-height: 100%;
+  vertical-align: middle;
+  content: ' ';
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-inline-vertical-adapt-layout:after {
+  display: inline-block;
+  width: 0;
+  min-height: 100%;
+  vertical-align: middle;
+  content: ' ';
+}
+@charset "UTF-8";
+/*!
+ * animate.css -http://daneden.me/animate
+ * Version - 3.5.1
+ * Licensed under the MIT license - http://opensource.org/licenses/MIT
+ *
+ * Copyright (c) 2016 Daniel Eden
+ */
+@-webkit-keyframes bounce {
+  from,
+  20%,
+  53%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  40%,
+  43% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -30px, 0);
+    transform: translate3d(0, -30px, 0);
+  }
+  70% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -15px, 0);
+    transform: translate3d(0, -15px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, -4px, 0);
+    transform: translate3d(0, -4px, 0);
+  }
+}
+@keyframes bounce {
+  from,
+  20%,
+  53%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  40%,
+  43% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -30px, 0);
+    transform: translate3d(0, -30px, 0);
+  }
+  70% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -15px, 0);
+    transform: translate3d(0, -15px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, -4px, 0);
+    transform: translate3d(0, -4px, 0);
+  }
+}
+@-webkit-keyframes flash {
+  from,
+  50%,
+  to {
+    opacity: 1;
+  }
+  25%,
+  75% {
+    opacity: 0;
+  }
+}
+@keyframes flash {
+  from,
+  50%,
+  to {
+    opacity: 1;
+  }
+  25%,
+  75% {
+    opacity: 0;
+  }
+}
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+@-webkit-keyframes pulse {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  50% {
+    -webkit-transform: scale3d(1.05, 1.05, 1.05);
+    transform: scale3d(1.05, 1.05, 1.05);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@keyframes pulse {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  50% {
+    -webkit-transform: scale3d(1.05, 1.05, 1.05);
+    transform: scale3d(1.05, 1.05, 1.05);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@-webkit-keyframes rubberBand {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  30% {
+    -webkit-transform: scale3d(1.25, 0.75, 1);
+    transform: scale3d(1.25, 0.75, 1);
+  }
+  40% {
+    -webkit-transform: scale3d(0.75, 1.25, 1);
+    transform: scale3d(0.75, 1.25, 1);
+  }
+  50% {
+    -webkit-transform: scale3d(1.15, 0.85, 1);
+    transform: scale3d(1.15, 0.85, 1);
+  }
+  65% {
+    -webkit-transform: scale3d(0.95, 1.05, 1);
+    transform: scale3d(0.95, 1.05, 1);
+  }
+  75% {
+    -webkit-transform: scale3d(1.05, 0.95, 1);
+    transform: scale3d(1.05, 0.95, 1);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@keyframes rubberBand {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  30% {
+    -webkit-transform: scale3d(1.25, 0.75, 1);
+    transform: scale3d(1.25, 0.75, 1);
+  }
+  40% {
+    -webkit-transform: scale3d(0.75, 1.25, 1);
+    transform: scale3d(0.75, 1.25, 1);
+  }
+  50% {
+    -webkit-transform: scale3d(1.15, 0.85, 1);
+    transform: scale3d(1.15, 0.85, 1);
+  }
+  65% {
+    -webkit-transform: scale3d(0.95, 1.05, 1);
+    transform: scale3d(0.95, 1.05, 1);
+  }
+  75% {
+    -webkit-transform: scale3d(1.05, 0.95, 1);
+    transform: scale3d(1.05, 0.95, 1);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@-webkit-keyframes shake {
+  from,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  10%,
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: translate3d(-10px, 0, 0);
+    transform: translate3d(-10px, 0, 0);
+  }
+  20%,
+  40%,
+  60%,
+  80% {
+    -webkit-transform: translate3d(10px, 0, 0);
+    transform: translate3d(10px, 0, 0);
+  }
+}
+@keyframes shake {
+  from,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  10%,
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: translate3d(-10px, 0, 0);
+    transform: translate3d(-10px, 0, 0);
+  }
+  20%,
+  40%,
+  60%,
+  80% {
+    -webkit-transform: translate3d(10px, 0, 0);
+    transform: translate3d(10px, 0, 0);
+  }
+}
+@-webkit-keyframes headShake {
+  0% {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+  }
+  6.5% {
+    -webkit-transform: translateX(-6px) rotateY(-9deg);
+    transform: translateX(-6px) rotateY(-9deg);
+  }
+  18.5% {
+    -webkit-transform: translateX(5px) rotateY(7deg);
+    transform: translateX(5px) rotateY(7deg);
+  }
+  31.5% {
+    -webkit-transform: translateX(-3px) rotateY(-5deg);
+    transform: translateX(-3px) rotateY(-5deg);
+  }
+  43.5% {
+    -webkit-transform: translateX(2px) rotateY(3deg);
+    transform: translateX(2px) rotateY(3deg);
+  }
+  50% {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+  }
+}
+@keyframes headShake {
+  0% {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+  }
+  6.5% {
+    -webkit-transform: translateX(-6px) rotateY(-9deg);
+    transform: translateX(-6px) rotateY(-9deg);
+  }
+  18.5% {
+    -webkit-transform: translateX(5px) rotateY(7deg);
+    transform: translateX(5px) rotateY(7deg);
+  }
+  31.5% {
+    -webkit-transform: translateX(-3px) rotateY(-5deg);
+    transform: translateX(-3px) rotateY(-5deg);
+  }
+  43.5% {
+    -webkit-transform: translateX(2px) rotateY(3deg);
+    transform: translateX(2px) rotateY(3deg);
+  }
+  50% {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+  }
+}
+@-webkit-keyframes swing {
+  20% {
+    -webkit-transform: rotate3d(0, 0, 1, 15deg);
+    transform: rotate3d(0, 0, 1, 15deg);
+  }
+  40% {
+    -webkit-transform: rotate3d(0, 0, 1, -10deg);
+    transform: rotate3d(0, 0, 1, -10deg);
+  }
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 5deg);
+    transform: rotate3d(0, 0, 1, 5deg);
+  }
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, -5deg);
+    transform: rotate3d(0, 0, 1, -5deg);
+  }
+  to {
+    -webkit-transform: rotate3d(0, 0, 1, 0deg);
+    transform: rotate3d(0, 0, 1, 0deg);
+  }
+}
+@keyframes swing {
+  20% {
+    -webkit-transform: rotate3d(0, 0, 1, 15deg);
+    transform: rotate3d(0, 0, 1, 15deg);
+  }
+  40% {
+    -webkit-transform: rotate3d(0, 0, 1, -10deg);
+    transform: rotate3d(0, 0, 1, -10deg);
+  }
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 5deg);
+    transform: rotate3d(0, 0, 1, 5deg);
+  }
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, -5deg);
+    transform: rotate3d(0, 0, 1, -5deg);
+  }
+  to {
+    -webkit-transform: rotate3d(0, 0, 1, 0deg);
+    transform: rotate3d(0, 0, 1, 0deg);
+  }
+}
+@-webkit-keyframes tada {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  10%,
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+  }
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+  }
+  40%,
+  60%,
+  80% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@keyframes tada {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+  10%,
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+  }
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+  }
+  40%,
+  60%,
+  80% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+  }
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+@-webkit-keyframes wobble {
+  from {
+    -webkit-transform: none;
+    transform: none;
+  }
+  15% {
+    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+  }
+  30% {
+    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+  }
+  45% {
+    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+  }
+  60% {
+    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+  }
+  75% {
+    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes wobble {
+  from {
+    -webkit-transform: none;
+    transform: none;
+  }
+  15% {
+    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+  }
+  30% {
+    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+  }
+  45% {
+    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+  }
+  60% {
+    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+  }
+  75% {
+    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes jello {
+  from,
+  11.1%,
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+  22.2% {
+    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
+    transform: skewX(-12.5deg) skewY(-12.5deg);
+  }
+  33.3% {
+    -webkit-transform: skewX(6.25deg) skewY(6.25deg);
+    transform: skewX(6.25deg) skewY(6.25deg);
+  }
+  44.4% {
+    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
+    transform: skewX(-3.125deg) skewY(-3.125deg);
+  }
+  55.5% {
+    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
+    transform: skewX(1.5625deg) skewY(1.5625deg);
+  }
+  66.6% {
+    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
+    transform: skewX(-0.78125deg) skewY(-0.78125deg);
+  }
+  77.7% {
+    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
+    transform: skewX(0.390625deg) skewY(0.390625deg);
+  }
+  88.8% {
+    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+  }
+}
+@keyframes jello {
+  from,
+  11.1%,
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+  22.2% {
+    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
+    transform: skewX(-12.5deg) skewY(-12.5deg);
+  }
+  33.3% {
+    -webkit-transform: skewX(6.25deg) skewY(6.25deg);
+    transform: skewX(6.25deg) skewY(6.25deg);
+  }
+  44.4% {
+    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
+    transform: skewX(-3.125deg) skewY(-3.125deg);
+  }
+  55.5% {
+    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
+    transform: skewX(1.5625deg) skewY(1.5625deg);
+  }
+  66.6% {
+    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
+    transform: skewX(-0.78125deg) skewY(-0.78125deg);
+  }
+  77.7% {
+    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
+    transform: skewX(0.390625deg) skewY(0.390625deg);
+  }
+  88.8% {
+    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+  }
+}
+@-webkit-keyframes bounceIn {
+  from,
+  20%,
+  40%,
+  60%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  20% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+  40% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.9);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(1.03, 1.03, 1.03);
+    transform: scale3d(1.03, 1.03, 1.03);
+  }
+  80% {
+    -webkit-transform: scale3d(0.97, 0.97, 0.97);
+    transform: scale3d(0.97, 0.97, 0.97);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@keyframes bounceIn {
+  from,
+  20%,
+  40%,
+  60%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  20% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+  40% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.9);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(1.03, 1.03, 1.03);
+    transform: scale3d(1.03, 1.03, 1.03);
+  }
+  80% {
+    -webkit-transform: scale3d(0.97, 0.97, 0.97);
+    transform: scale3d(0.97, 0.97, 0.97);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+@-webkit-keyframes bounceInDown {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -3000px, 0);
+    transform: translate3d(0, -3000px, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 25px, 0);
+    transform: translate3d(0, 25px, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(0, -10px, 0);
+    transform: translate3d(0, -10px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, 5px, 0);
+    transform: translate3d(0, 5px, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes bounceInDown {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -3000px, 0);
+    transform: translate3d(0, -3000px, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 25px, 0);
+    transform: translate3d(0, 25px, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(0, -10px, 0);
+    transform: translate3d(0, -10px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, 5px, 0);
+    transform: translate3d(0, 5px, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes bounceInLeft {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: translate3d(-3000px, 0, 0);
+    transform: translate3d(-3000px, 0, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(25px, 0, 0);
+    transform: translate3d(25px, 0, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(-10px, 0, 0);
+    transform: translate3d(-10px, 0, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(5px, 0, 0);
+    transform: translate3d(5px, 0, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes bounceInLeft {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  0% {
+    opacity: 0;
+    -webkit-transform: translate3d(-3000px, 0, 0);
+    transform: translate3d(-3000px, 0, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(25px, 0, 0);
+    transform: translate3d(25px, 0, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(-10px, 0, 0);
+    transform: translate3d(-10px, 0, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(5px, 0, 0);
+    transform: translate3d(5px, 0, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes bounceInRight {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(3000px, 0, 0);
+    transform: translate3d(3000px, 0, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(-25px, 0, 0);
+    transform: translate3d(-25px, 0, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(10px, 0, 0);
+    transform: translate3d(10px, 0, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(-5px, 0, 0);
+    transform: translate3d(-5px, 0, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes bounceInRight {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(3000px, 0, 0);
+    transform: translate3d(3000px, 0, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(-25px, 0, 0);
+    transform: translate3d(-25px, 0, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(10px, 0, 0);
+    transform: translate3d(10px, 0, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(-5px, 0, 0);
+    transform: translate3d(-5px, 0, 0);
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes bounceInUp {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 3000px, 0);
+    transform: translate3d(0, 3000px, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, -20px, 0);
+    transform: translate3d(0, -20px, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(0, 10px, 0);
+    transform: translate3d(0, 10px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, -5px, 0);
+    transform: translate3d(0, -5px, 0);
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@keyframes bounceInUp {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 3000px, 0);
+    transform: translate3d(0, 3000px, 0);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, -20px, 0);
+    transform: translate3d(0, -20px, 0);
+  }
+  75% {
+    -webkit-transform: translate3d(0, 10px, 0);
+    transform: translate3d(0, 10px, 0);
+  }
+  90% {
+    -webkit-transform: translate3d(0, -5px, 0);
+    transform: translate3d(0, -5px, 0);
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@-webkit-keyframes bounceOut {
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.9);
+  }
+  50%,
+  55% {
+    opacity: 1;
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+}
+@keyframes bounceOut {
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.9);
+  }
+  50%,
+  55% {
+    opacity: 1;
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+}
+@-webkit-keyframes bounceOutDown {
+  20% {
+    -webkit-transform: translate3d(0, 10px, 0);
+    transform: translate3d(0, 10px, 0);
+  }
+  40%,
+  45% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, -20px, 0);
+    transform: translate3d(0, -20px, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+}
+@keyframes bounceOutDown {
+  20% {
+    -webkit-transform: translate3d(0, 10px, 0);
+    transform: translate3d(0, 10px, 0);
+  }
+  40%,
+  45% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, -20px, 0);
+    transform: translate3d(0, -20px, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+}
+@-webkit-keyframes bounceOutLeft {
+  20% {
+    opacity: 1;
+    -webkit-transform: translate3d(20px, 0, 0);
+    transform: translate3d(20px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+@keyframes bounceOutLeft {
+  20% {
+    opacity: 1;
+    -webkit-transform: translate3d(20px, 0, 0);
+    transform: translate3d(20px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+@-webkit-keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    -webkit-transform: translate3d(-20px, 0, 0);
+    transform: translate3d(-20px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+@keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    -webkit-transform: translate3d(-20px, 0, 0);
+    transform: translate3d(-20px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+@-webkit-keyframes bounceOutUp {
+  20% {
+    -webkit-transform: translate3d(0, -10px, 0);
+    transform: translate3d(0, -10px, 0);
+  }
+  40%,
+  45% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 20px, 0);
+    transform: translate3d(0, 20px, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+}
+@keyframes bounceOutUp {
+  20% {
+    -webkit-transform: translate3d(0, -10px, 0);
+    transform: translate3d(0, -10px, 0);
+  }
+  40%,
+  45% {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 20px, 0);
+    transform: translate3d(0, 20px, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+}
+@-webkit-keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+@-webkit-keyframes fadeInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInDownBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInDownBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInLeftBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInLeftBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInRightBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInRightBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeInUpBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes fadeInUpBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@-webkit-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-webkit-keyframes fadeOutDown {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+@keyframes fadeOutDown {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+@-webkit-keyframes fadeOutDownBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+}
+@keyframes fadeOutDownBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+}
+@-webkit-keyframes fadeOutLeft {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+@keyframes fadeOutLeft {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+@-webkit-keyframes fadeOutLeftBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+@keyframes fadeOutLeftBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+@-webkit-keyframes fadeOutRight {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+@keyframes fadeOutRight {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+@-webkit-keyframes fadeOutRightBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+@keyframes fadeOutRightBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+@-webkit-keyframes fadeOutUp {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+@keyframes fadeOutUp {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+@-webkit-keyframes fadeOutUpBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+}
+@keyframes fadeOutUpBig {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+}
+@-webkit-keyframes flip {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+  40% {
+    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+  50% {
+    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  80% {
+    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95);
+    transform: perspective(400px) scale3d(0.95, 0.95, 0.95);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+}
+@keyframes flip {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+  40% {
+    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+  50% {
+    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  80% {
+    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95);
+    transform: perspective(400px) scale3d(0.95, 0.95, 0.95);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+}
+@-webkit-keyframes flipInX {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+@keyframes flipInX {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+@-webkit-keyframes flipInY {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+@keyframes flipInY {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+  }
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+@-webkit-keyframes flipOutX {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    opacity: 0;
+  }
+}
+@keyframes flipOutX {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes flipOutY {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    opacity: 0;
+  }
+}
+@keyframes flipOutY {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes lightSpeedIn {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+    transform: translate3d(100%, 0, 0) skewX(-30deg);
+    opacity: 0;
+  }
+  60% {
+    -webkit-transform: skewX(20deg);
+    transform: skewX(20deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: skewX(-5deg);
+    transform: skewX(-5deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes lightSpeedIn {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+    transform: translate3d(100%, 0, 0) skewX(-30deg);
+    opacity: 0;
+  }
+  60% {
+    -webkit-transform: skewX(20deg);
+    transform: skewX(20deg);
+    opacity: 1;
+  }
+  80% {
+    -webkit-transform: skewX(-5deg);
+    transform: skewX(-5deg);
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes lightSpeedOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+    transform: translate3d(100%, 0, 0) skewX(30deg);
+    opacity: 0;
+  }
+}
+@keyframes lightSpeedOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+    transform: translate3d(100%, 0, 0) skewX(30deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes rotateIn {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, -200deg);
+    transform: rotate3d(0, 0, 1, -200deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes rotateIn {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, -200deg);
+    transform: rotate3d(0, 0, 1, -200deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes rotateInDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes rotateInDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes rotateInDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes rotateInDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes rotateInUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes rotateInUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes rotateInUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -90deg);
+    transform: rotate3d(0, 0, 1, -90deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@keyframes rotateInUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -90deg);
+    transform: rotate3d(0, 0, 1, -90deg);
+    opacity: 0;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: none;
+    transform: none;
+    opacity: 1;
+  }
+}
+@-webkit-keyframes rotateOut {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, 200deg);
+    transform: rotate3d(0, 0, 1, 200deg);
+    opacity: 0;
+  }
+}
+@keyframes rotateOut {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, 200deg);
+    transform: rotate3d(0, 0, 1, 200deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes rotateOutDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+}
+@keyframes rotateOutDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes rotateOutDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+@keyframes rotateOutDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes rotateOutUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+@keyframes rotateOutUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes rotateOutUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 90deg);
+    transform: rotate3d(0, 0, 1, 90deg);
+    opacity: 0;
+  }
+}
+@keyframes rotateOutUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 90deg);
+    transform: rotate3d(0, 0, 1, 90deg);
+    opacity: 0;
+  }
+}
+@-webkit-keyframes hinge {
+  0% {
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+  20%,
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 80deg);
+    transform: rotate3d(0, 0, 1, 80deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+  40%,
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, 60deg);
+    transform: rotate3d(0, 0, 1, 60deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: translate3d(0, 700px, 0);
+    transform: translate3d(0, 700px, 0);
+    opacity: 0;
+  }
+}
+@keyframes hinge {
+  0% {
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+  20%,
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 80deg);
+    transform: rotate3d(0, 0, 1, 80deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+  40%,
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, 60deg);
+    transform: rotate3d(0, 0, 1, 60deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+    opacity: 1;
+  }
+  to {
+    -webkit-transform: translate3d(0, 700px, 0);
+    transform: translate3d(0, 700px, 0);
+    opacity: 0;
+  }
+}
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+@-webkit-keyframes rollIn {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+@keyframes rollIn {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+  }
+  to {
+    opacity: 1;
+    -webkit-transform: none;
+    transform: none;
+  }
+}
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+@-webkit-keyframes rollOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+  }
+}
+@keyframes rollOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+  }
+}
+@-webkit-keyframes zoomIn {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  50% {
+    opacity: 1;
+  }
+}
+@keyframes zoomIn {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  50% {
+    opacity: 1;
+  }
+}
+@-webkit-keyframes zoomInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes zoomInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes zoomInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes zoomInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes zoomOut {
+  from {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  to {
+    opacity: 0;
+  }
+}
+@keyframes zoomOut {
+  from {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+  to {
+    opacity: 0;
+  }
+}
+@-webkit-keyframes zoomOutDown {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomOutDown {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes zoomOutLeft {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
+    transform: scale(0.1) translate3d(-2000px, 0, 0);
+    -webkit-transform-origin: left center;
+    transform-origin: left center;
+  }
+}
+@keyframes zoomOutLeft {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
+    transform: scale(0.1) translate3d(-2000px, 0, 0);
+    -webkit-transform-origin: left center;
+    transform-origin: left center;
+  }
+}
+@-webkit-keyframes zoomOutRight {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
+    transform: scale(0.1) translate3d(2000px, 0, 0);
+    -webkit-transform-origin: right center;
+    transform-origin: right center;
+  }
+}
+@keyframes zoomOutRight {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
+    transform: scale(0.1) translate3d(2000px, 0, 0);
+    -webkit-transform-origin: right center;
+    transform-origin: right center;
+  }
+}
+@-webkit-keyframes zoomOutUp {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@keyframes zoomOutUp {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+@-webkit-keyframes slideInDown {
+  from {
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@keyframes slideInDown {
+  from {
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@-webkit-keyframes slideInLeft {
+  from {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@keyframes slideInLeft {
+  from {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@-webkit-keyframes slideInRight {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@keyframes slideInRight {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@-webkit-keyframes slideInUp {
+  from {
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@keyframes slideInUp {
+  from {
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+    visibility: visible;
+  }
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+@-webkit-keyframes slideOutDown {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+@keyframes slideOutDown {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+@-webkit-keyframes slideOutLeft {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+@keyframes slideOutLeft {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+@-webkit-keyframes slideOutRight {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+@keyframes slideOutRight {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+@-webkit-keyframes slideOutUp {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+@keyframes slideOutUp {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+.animated {
+  -webkit-animation-duration: 1s;
+  animation-duration: 1s;
+  -webkit-animation-fill-mode: both;
+  animation-fill-mode: both;
+}
+.animated.infinite {
+  -webkit-animation-iteration-count: infinite;
+  animation-iteration-count: infinite;
+}
+.bounce {
+  -webkit-animation-name: bounce;
+  animation-name: bounce;
+  -webkit-transform-origin: center bottom;
+  transform-origin: center bottom;
+}
+.flash {
+  -webkit-animation-name: flash;
+  animation-name: flash;
+}
+.pulse {
+  -webkit-animation-name: pulse;
+  animation-name: pulse;
+}
+.rubberBand {
+  -webkit-animation-name: rubberBand;
+  animation-name: rubberBand;
+}
+.shake {
+  -webkit-animation-name: shake;
+  animation-name: shake;
+}
+.headShake {
+  -webkit-animation-timing-function: ease-in-out;
+  animation-timing-function: ease-in-out;
+  -webkit-animation-name: headShake;
+  animation-name: headShake;
+}
+.swing {
+  -webkit-transform-origin: top center;
+  transform-origin: top center;
+  -webkit-animation-name: swing;
+  animation-name: swing;
+}
+.tada {
+  -webkit-animation-name: tada;
+  animation-name: tada;
+}
+.jello {
+  -webkit-animation-name: jello;
+  animation-name: jello;
+  -webkit-transform-origin: center;
+  transform-origin: center;
+}
+.bounceIn {
+  -webkit-animation-duration: .75s;
+  animation-duration: .75s;
+  -webkit-animation-name: bounceIn;
+  animation-name: bounceIn;
+}
+.bounceInDown {
+  -webkit-animation-name: bounceInDown;
+  animation-name: bounceInDown;
+}
+.bounceInLeft {
+  -webkit-animation-name: bounceInLeft;
+  animation-name: bounceInLeft;
+}
+.bounceInRight {
+  -webkit-animation-name: bounceInRight;
+  animation-name: bounceInRight;
+}
+.bounceInUp {
+  -webkit-animation-name: bounceInUp;
+  animation-name: bounceInUp;
+}
+.bounceOut {
+  -webkit-animation-duration: .75s;
+  animation-duration: .75s;
+  -webkit-animation-name: bounceOut;
+  animation-name: bounceOut;
+}
+.bounceOutDown {
+  -webkit-animation-name: bounceOutDown;
+  animation-name: bounceOutDown;
+}
+.bounceOutLeft {
+  -webkit-animation-name: bounceOutLeft;
+  animation-name: bounceOutLeft;
+}
+.bounceOutRight {
+  -webkit-animation-name: bounceOutRight;
+  animation-name: bounceOutRight;
+}
+.bounceOutUp {
+  -webkit-animation-name: bounceOutUp;
+  animation-name: bounceOutUp;
+}
+.fadeIn {
+  -webkit-animation-name: fadeIn;
+  animation-name: fadeIn;
+}
+.fadeInDown {
+  -webkit-animation-name: fadeInDown;
+  animation-name: fadeInDown;
+}
+.fadeInDownBig {
+  -webkit-animation-name: fadeInDownBig;
+  animation-name: fadeInDownBig;
+}
+.fadeInLeft {
+  -webkit-animation-name: fadeInLeft;
+  animation-name: fadeInLeft;
+}
+.fadeInLeftBig {
+  -webkit-animation-name: fadeInLeftBig;
+  animation-name: fadeInLeftBig;
+}
+.fadeInRight {
+  -webkit-animation-name: fadeInRight;
+  animation-name: fadeInRight;
+}
+.fadeInRightBig {
+  -webkit-animation-name: fadeInRightBig;
+  animation-name: fadeInRightBig;
+}
+.fadeInUp {
+  -webkit-animation-name: fadeInUp;
+  animation-name: fadeInUp;
+}
+.fadeInUpBig {
+  -webkit-animation-name: fadeInUpBig;
+  animation-name: fadeInUpBig;
+}
+.fadeOut {
+  -webkit-animation-name: fadeOut;
+  animation-name: fadeOut;
+}
+.fadeOutDown {
+  -webkit-animation-name: fadeOutDown;
+  animation-name: fadeOutDown;
+}
+.fadeOutDownBig {
+  -webkit-animation-name: fadeOutDownBig;
+  animation-name: fadeOutDownBig;
+}
+.fadeOutLeft {
+  -webkit-animation-name: fadeOutLeft;
+  animation-name: fadeOutLeft;
+}
+.fadeOutLeftBig {
+  -webkit-animation-name: fadeOutLeftBig;
+  animation-name: fadeOutLeftBig;
+}
+.fadeOutRight {
+  -webkit-animation-name: fadeOutRight;
+  animation-name: fadeOutRight;
+}
+.fadeOutRightBig {
+  -webkit-animation-name: fadeOutRightBig;
+  animation-name: fadeOutRightBig;
+}
+.fadeOutUp {
+  -webkit-animation-name: fadeOutUp;
+  animation-name: fadeOutUp;
+}
+.fadeOutUpBig {
+  -webkit-animation-name: fadeOutUpBig;
+  animation-name: fadeOutUpBig;
+}
+.flip {
+  -webkit-backface-visibility: visible;
+  backface-visibility: visible;
+  -webkit-animation-name: flip;
+  animation-name: flip;
+}
+.flipInX {
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+  -webkit-animation-name: flipInX;
+  animation-name: flipInX;
+}
+.flipInY {
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+  -webkit-animation-name: flipInY;
+  animation-name: flipInY;
+}
+.flipOutX {
+  -webkit-animation-duration: .75s;
+  animation-duration: .75s;
+  -webkit-animation-name: flipOutX;
+  animation-name: flipOutX;
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+}
+.flipOutY {
+  -webkit-animation-duration: .75s;
+  animation-duration: .75s;
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+  -webkit-animation-name: flipOutY;
+  animation-name: flipOutY;
+}
+.lightSpeedIn {
+  -webkit-animation-name: lightSpeedIn;
+  animation-name: lightSpeedIn;
+  -webkit-animation-timing-function: ease-out;
+  animation-timing-function: ease-out;
+}
+.lightSpeedOut {
+  -webkit-animation-name: lightSpeedOut;
+  animation-name: lightSpeedOut;
+  -webkit-animation-timing-function: ease-in;
+  animation-timing-function: ease-in;
+}
+.rotateIn {
+  -webkit-animation-name: rotateIn;
+  animation-name: rotateIn;
+}
+.rotateInDownLeft {
+  -webkit-animation-name: rotateInDownLeft;
+  animation-name: rotateInDownLeft;
+}
+.rotateInDownRight {
+  -webkit-animation-name: rotateInDownRight;
+  animation-name: rotateInDownRight;
+}
+.rotateInUpLeft {
+  -webkit-animation-name: rotateInUpLeft;
+  animation-name: rotateInUpLeft;
+}
+.rotateInUpRight {
+  -webkit-animation-name: rotateInUpRight;
+  animation-name: rotateInUpRight;
+}
+.rotateOut {
+  -webkit-animation-name: rotateOut;
+  animation-name: rotateOut;
+}
+.rotateOutDownLeft {
+  -webkit-animation-name: rotateOutDownLeft;
+  animation-name: rotateOutDownLeft;
+}
+.rotateOutDownRight {
+  -webkit-animation-name: rotateOutDownRight;
+  animation-name: rotateOutDownRight;
+}
+.rotateOutUpLeft {
+  -webkit-animation-name: rotateOutUpLeft;
+  animation-name: rotateOutUpLeft;
+}
+.hinge {
+  -webkit-animation-duration: 2s;
+  animation-duration: 2s;
+  -webkit-animation-name: hinge;
+  animation-name: hinge;
+}
+.rollIn {
+  -webkit-animation-name: rollIn;
+  animation-name: rollIn;
+}
+.rollOut {
+  -webkit-animation-name: rollOut;
+  animation-name: rollOut;
+}
+.zoomIn {
+  -webkit-animation-name: zoomIn;
+  animation-name: zoomIn;
+}
+.zoomInDown {
+  -webkit-animation-name: zoomInDown;
+  animation-name: zoomInDown;
+}
+.zoomInLeft {
+  -webkit-animation-name: zoomInLeft;
+  animation-name: zoomInLeft;
+}
+.zoomInRight {
+  -webkit-animation-name: zoomInRight;
+  animation-name: zoomInRight;
+}
+.zoomInUp {
+  -webkit-animation-name: zoomInUp;
+  animation-name: zoomInUp;
+}
+.zoomOut {
+  -webkit-animation-name: zoomOut;
+  animation-name: zoomOut;
+}
+.zoomOutDown {
+  -webkit-animation-name: zoomOutDown;
+  animation-name: zoomOutDown;
+}
+.zoomOutLeft {
+  -webkit-animation-name: zoomOutLeft;
+  animation-name: zoomOutLeft;
+}
+.zoomOutRight {
+  -webkit-animation-name: zoomOutRight;
+  animation-name: zoomOutRight;
+}
+.zoomOutUp {
+  -webkit-animation-name: zoomOutUp;
+  animation-name: zoomOutUp;
+}
+.slideInDown {
+  -webkit-animation-name: slideInDown;
+  animation-name: slideInDown;
+}
+.slideInLeft {
+  -webkit-animation-name: slideInLeft;
+  animation-name: slideInLeft;
+}
+.slideInRight {
+  -webkit-animation-name: slideInRight;
+  animation-name: slideInRight;
+}
+.slideInUp {
+  -webkit-animation-name: slideInUp;
+  animation-name: slideInUp;
+}
+.slideOutDown {
+  -webkit-animation-name: slideOutDown;
+  animation-name: slideOutDown;
+}
+.slideOutLeft {
+  -webkit-animation-name: slideOutLeft;
+  animation-name: slideOutLeft;
+}
+.slideOutRight {
+  -webkit-animation-name: slideOutRight;
+  animation-name: slideOutRight;
+}
+.slideOutUp {
+  -webkit-animation-name: slideOutUp;
+  animation-name: slideOutUp;
+}
+.base-line-conn-background {
+  background: url('icon/tree-vertical-line-1.png') repeat-y 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-1.png');
+  _background: none;
+}
+.first-line-conn-background {
+  background: url('icon/tree-vertical-line-2.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
+  _background: none;
+}
+.last-line-conn-background {
+  background: url('icon/tree-vertical-line-4.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
+  _background: none;
+}
+.mid-line-conn-background {
+  background: url('icon/tree-vertical-line-3.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
+  _background: none;
+}
+.loading-background {
+  background: url('icon/loading.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading.gif');
+  _background: none;
+}
+.loading-background-f25 {
+  background: url('background/F.25.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/F.25.gif');
+  _background: none;
+}
+.loading-background-e50 {
+  background: url('background/E.50.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/E.50.gif');
+  _background: none;
+}
+.loading-background-d100 {
+  background: url('background/D.100.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/D.100.gif');
+  _background: none;
+}
+.axis-tip-background {
+  background: url('background/charts/axis.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-accu-tip-background {
+  background: url('background/charts/axis_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_accu.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-percent-tip-background {
+  background: url('background/charts/axis_percent.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_percent.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-compare-tip-background {
+  background: url('background/charts/axis_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_compare.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-fall-tip-background {
+  background: url('background/charts/axis_fall.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_fall.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bubble-tip-background {
+  background: url('background/charts/bubble.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bubble.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bubble-force-tip-background {
+  background: url('background/charts/bubble_force.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bubble_force.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.dashboard-tip-background {
+  background: url('background/charts/dashboard.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/dashboard.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.donut-tip-background {
+  background: url('background/charts/donut.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/donut.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.funnel-tip-background {
+  background: url('background/charts/funnel.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/funnel.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-tip-background {
+  background: url('background/charts/map.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-gis-tip-background {
+  background: url('background/charts/map_gis.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_gis.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-tip-background {
+  background: url('background/charts/map_svg.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-c-tip-background {
+  background: url('background/charts/map_svg_c.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg_c.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-g-tip-background {
+  background: url('background/charts/map_svg_g.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg_g.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.pie-tip-background {
+  background: url('background/charts/pie.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/pie.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.radar-tip-background {
+  background: url('background/charts/radar.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/radar.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.radar-accu-tip-background {
+  background: url('background/charts/radar_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/radar_accu.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-tip-background {
+  background: url('background/charts/area.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-accu-tip-background {
+  background: url('background/charts/area_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_accu.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-compare-tip-background {
+  background: url('background/charts/area_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_compare.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-percent-tip-background {
+  background: url('background/charts/area_percent.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_percent.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-range-tip-background {
+  background: url('background/charts/area_range.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_range.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-tip-background {
+  background: url('background/charts/bar.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-accu-tip-background {
+  background: url('background/charts/bar_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar_accu.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-compare-tip-background {
+  background: url('background/charts/bar_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar_compare.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.combine-tip-background {
+  background: url('background/charts/combine.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/combine.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.combine-m-tip-background {
+  background: url('background/charts/combine_m.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/combine_m.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.line-tip-background {
+  background: url('background/charts/line.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/line.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.scatter-tip-background {
+  background: url('background/charts/scatter.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/scatter.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-complex-tip-background {
+  background: url('background/charts/table_complex.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_complex.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-cross-tip-background {
+  background: url('background/charts/table_cross.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_cross.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-group-tip-background {
+  background: url('background/charts/table_group.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_group.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-detail-tip-background {
+  background: url('background/charts/table_detail.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_detail.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-text-tip-background {
+  background: url('background/charts/text/axis_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-accu-text-tip-background {
+  background: url('background/charts/text/axis_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_accu_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-percent-text-tip-background {
+  background: url('background/charts/text/axis_percent_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_percent_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-compare-text-tip-background {
+  background: url('background/charts/text/axis_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_compare_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.axis-fall-text-tip-background {
+  background: url('background/charts/text/axis_fall_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_fall_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bubble-text-tip-background {
+  background: url('background/charts/text/bubble_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bubble_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bubble-force-text-tip-background {
+  background: url('background/charts/text/bubble_force_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bubble_force_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.dashboard-text-tip-background {
+  background: url('background/charts/text/dashboard_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/dashboard_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.donut-text-tip-background {
+  background: url('background/charts/text/donut_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/donut_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.funnel-text-tip-background {
+  background: url('background/charts/text/funnel_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/funnel_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-text-tip-background {
+  background: url('background/charts/text/map_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-gis-text-tip-background {
+  background: url('background/charts/text/map_gis_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_gis_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-text-tip-background {
+  background: url('background/charts/text/map_svg_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-c-text-tip-background {
+  background: url('background/charts/text/map_svg_c_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_c_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.map-svg-g-text-tip-background {
+  background: url('background/charts/text/map_svg_g_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_g_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.pie-text-tip-background {
+  background: url('background/charts/text/pie_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/pie_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.radar-text-tip-background {
+  background: url('background/charts/text/radar_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/radar_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.radar-accu-text-tip-background {
+  background: url('background/charts/text/radar_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/radar_accu_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-text-tip-background {
+  background: url('background/charts/text/area_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-accu-text-tip-background {
+  background: url('background/charts/text/area_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_accu_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-compare-text-tip-background {
+  background: url('background/charts/text/area_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_compare_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-percent-text-tip-background {
+  background: url('background/charts/text/area_percent_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_percent_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.area-range-text-tip-background {
+  background: url('background/charts/text/area_range_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_range_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-text-tip-background {
+  background: url('background/charts/text/bar_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-accu-text-tip-background {
+  background: url('background/charts/text/bar_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_accu_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.bar-compare-text-tip-background {
+  background: url('background/charts/text/bar_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_compare_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.combine-text-tip-background {
+  background: url('background/charts/text/combine_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/combine_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.combine-m-text-tip-background {
+  background: url('background/charts/text/combine_m_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/combine_m_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.line-text-tip-background {
+  background: url('background/charts/text/line_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/line_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.scatter-text-tip-background {
+  background: url('background/charts/text/text/scatter_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/text/scatter_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-complex-text-tip-background {
+  background: url('background/charts/text/table_complex_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_complex_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-cross-text-tip-background {
+  background: url('background/charts/text/table_cross_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_cross_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-group-text-tip-background {
+  background: url('background/charts/text/table_group_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_group_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.table-detail-text-tip-background {
+  background: url('background/charts/text/table_detail_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_detail_text.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+.data-miss-background {
+  background: url('background/data_miss.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/data_miss.png');
+  _background: none;
+  background-color: #ffffff;
+  z-index: 2;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.base-disabled {
+  cursor: default !important;
+  color: #c4c6c6 !important;
+}
+.base-disabled .b-font:before {
+  color: #c4c6c6 !important;
+}
+.base-invalid {
+  cursor: default !important;
+}
+.clearfix {
+  *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+  content: " ";
+  display: table;
+  line-height: 0;
+}
+.clearfix:after {
+  clear: both;
+}
+.bi-keyword-red-mark {
+  color: #f07d0a;
+}
+.bi-high-light {
+  color: #009de3;
+}
+.bi-water-mark {
+  color: #cccccc;
+  cursor: text;
+}
+.bi-tips {
+  color: #c4c6c6;
+}
+.bi-resizer {
+  background: #d8f3fe;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+  z-index: 1000000000;
+}
+.bi-z-index-mask {
+  background-color: #1a1a1a;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+.bi-list-item:hover,
+.bi-list-item.hover {
+  background-color: #f4f4f4;
+}
+.bi-list-item.disabled,
+.bi-list-item.disabled:hover,
+.bi-list-item.disabled:active {
+  background-color: #ffffff;
+}
+.bi-list-item-effect.active,
+.bi-list-item-effect:active {
+  color: #009de3;
+}
+.bi-list-item-effect.disabled,
+.bi-list-item-effect.disabled:hover,
+.bi-list-item-effect.disabled:active {
+  color: #1a1a1a;
+}
+.bi-list-item-hover:hover,
+.bi-list-item-hover.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-list-item-hover.disabled,
+.bi-list-item-hover.disabled:hover,
+.bi-list-item-hover.disabled:active {
+  color: #1a1a1a;
+  background-color: #ffffff;
+}
+.bi-list-item-active:hover,
+.bi-list-item-active.hover {
+  background-color: #f4f4f4;
+}
+.bi-list-item-active.active,
+.bi-list-item-active:active {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-list-item-active.disabled,
+.bi-list-item-active.disabled:hover,
+.bi-list-item-active.disabled:active {
+  background-color: #ffffff;
+}
+.bi-list-item-select:hover,
+.bi-list-item-select.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-list-item-select:active,
+.bi-list-item-select.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+.bi-list-item-select:active .bi-high-light,
+.bi-list-item-select.active .bi-high-light {
+  color: #ffffff;
+}
+.bi-list-item-select.disabled,
+.bi-list-item-select.disabled:hover,
+.bi-list-item-select.disabled:active {
+  color: #c4c6c6 !important;
+  background-color: #ffffff !important;
+}
+.bi-list-item-select.disabled .bi-high-light,
+.bi-list-item-select.disabled:hover .bi-high-light,
+.bi-list-item-select.disabled:active .bi-high-light {
+  color: #c4c6c6 !important;
+}
+/*****************cursor*****************/
+.cursor-pointer {
+  cursor: pointer;
+}
+.cursor-default {
+  cursor: default;
+}
+.cursor-move {
+  cursor: move;
+}
+/*****************cursor*****************/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.close-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-font.native .b-font:before,
+.close-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-red-font .b-font:before {
+  content: "\e600";
+  color: #e85050;
+}
+.close-red-font.native .b-font:before,
+.close-red-font.disabled .b-font:before {
+  content: "\e600";
+  color: #e85050;
+}
+.close-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-h-font:hover .b-font:before,
+.close-h-font:focus .b-font:before,
+.close-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-h-font.native .b-font:before,
+.close-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-e-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-e-font:hover .b-font:before,
+.close-e-font:focus .b-font:before,
+.close-e-font.hover .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-e-font.active .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.close-e-font:active .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.close-e-font.native .b-font:before,
+.close-e-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-ha-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-ha-font:hover .b-font:before,
+.close-ha-font:focus .b-font:before,
+.close-ha-font.hover .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.close-ha-font:active .b-font:before,
+.close-ha-font.active .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.close-ha-font.native .b-font:before,
+.close-ha-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.search-close-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.search-close-h-font:hover .b-font:before,
+.search-close-h-font:focus .b-font:before,
+.search-close-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #e85050;
+}
+.search-close-h-font.native .b-font:before,
+.search-close-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.trigger-font .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-font.native .b-font:before,
+.trigger-font.disabled .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-h-font .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-h-font:hover .b-font:before,
+.trigger-h-font:focus .b-font:before,
+.trigger-h-font.hover .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-h-font.native .b-font:before,
+.trigger-h-font.disabled .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-ha-font .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-ha-font:hover .b-font:before,
+.trigger-ha-font:focus .b-font:before,
+.trigger-ha-font.hover .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.trigger-ha-font:active .b-font:before,
+.trigger-ha-font.active .b-font:before {
+  content: "\e603";
+  color: #009de3;
+}
+.trigger-ha-font.native .b-font:before,
+.trigger-ha-font.disabled .b-font:before {
+  content: "\e603";
+  color: #808080;
+}
+.pre-page-font .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-font.native .b-font:before,
+.pre-page-font.disabled .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-h-font .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-h-font:hover .b-font:before,
+.pre-page-h-font:focus .b-font:before,
+.pre-page-h-font.hover .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-h-font.native .b-font:before,
+.pre-page-h-font.disabled .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-ha-font .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-ha-font:hover .b-font:before,
+.pre-page-ha-font:focus .b-font:before,
+.pre-page-ha-font.hover .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.pre-page-ha-font:active .b-font:before,
+.pre-page-ha-font.active .b-font:before {
+  content: "\e601";
+  color: #009de3;
+}
+.pre-page-ha-font.native .b-font:before,
+.pre-page-ha-font.disabled .b-font:before {
+  content: "\e601";
+  color: #808080;
+}
+.next-page-font .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-font.native .b-font:before,
+.next-page-font.disabled .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-h-font .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-h-font:hover .b-font:before,
+.next-page-h-font:focus .b-font:before,
+.next-page-h-font.hover .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-h-font.native .b-font:before,
+.next-page-h-font.disabled .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-ha-font .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-ha-font:hover .b-font:before,
+.next-page-ha-font:focus .b-font:before,
+.next-page-ha-font.hover .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.next-page-ha-font:active .b-font:before,
+.next-page-ha-font.active .b-font:before {
+  content: "\e602";
+  color: #009de3;
+}
+.next-page-ha-font.native .b-font:before,
+.next-page-ha-font.disabled .b-font:before {
+  content: "\e602";
+  color: #808080;
+}
+.search-font .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-font.native .b-font:before,
+.search-font.disabled .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-h-font .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-h-font:hover .b-font:before,
+.search-h-font:focus .b-font:before,
+.search-h-font.hover .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-h-font.native .b-font:before,
+.search-h-font.disabled .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-ha-font .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-ha-font:hover .b-font:before,
+.search-ha-font:focus .b-font:before,
+.search-ha-font.hover .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.search-ha-font:active .b-font:before,
+.search-ha-font.active .b-font:before {
+  content: "\e604";
+  color: #009de3;
+}
+.search-ha-font.native .b-font:before,
+.search-ha-font.disabled .b-font:before {
+  content: "\e604";
+  color: #808080;
+}
+.share-font .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-font.native .b-font:before,
+.share-font.disabled .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-h-font .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-h-font:hover .b-font:before,
+.share-h-font:focus .b-font:before,
+.share-h-font.hover .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-h-font.native .b-font:before,
+.share-h-font.disabled .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-ha-font .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-ha-font:hover .b-font:before,
+.share-ha-font:focus .b-font:before,
+.share-ha-font.hover .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-ha-font:active .b-font:before,
+.share-ha-font.active .b-font:before {
+  content: "\e65a";
+  color: #009de3;
+}
+.share-ha-font.native .b-font:before,
+.share-ha-font.disabled .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+/**维度/指标 下拉列表图标字体 ~begin~**/
+.delete-font .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-font.native .b-font:before,
+.delete-font.disabled .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-h-font .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-h-font:hover .b-font:before,
+.delete-h-font:focus .b-font:before,
+.delete-h-font.hover .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-h-font.native .b-font:before,
+.delete-h-font.disabled .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-ha-font .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-ha-font:hover .b-font:before,
+.delete-ha-font:focus .b-font:before,
+.delete-ha-font.hover .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-ha-font:active .b-font:before,
+.delete-ha-font.active .b-font:before {
+  content: "\e605";
+  color: #009de3;
+}
+.delete-ha-font.native .b-font:before,
+.delete-ha-font.disabled .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-e-font .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-e-font:hover .b-font:before,
+.delete-e-font:focus .b-font:before,
+.delete-e-font.hover .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.delete-e-font.active .b-font:before {
+  content: "\e605";
+  color: #009de3;
+}
+.delete-e-font:active .b-font:before {
+  content: "\e605";
+  color: #009de3;
+}
+.delete-e-font.native .b-font:before,
+.delete-e-font.disabled .b-font:before {
+  content: "\e605";
+  color: #1a1a1a;
+}
+.dot-font .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-font.native .b-font:before,
+.dot-font.disabled .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-h-font .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-h-font:hover .b-font:before,
+.dot-h-font:focus .b-font:before,
+.dot-h-font.hover .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-h-font.native .b-font:before,
+.dot-h-font.disabled .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-ha-font .b-font:before {
+  content: "\e606";
+  color: #ffffff;
+}
+.dot-ha-font:hover .b-font:before,
+.dot-ha-font:focus .b-font:before,
+.dot-ha-font.hover .b-font:before {
+  content: "\e606";
+  color: #f4f4f4;
+}
+.dot-ha-font:active .b-font:before,
+.dot-ha-font.active .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-ha-font.native .b-font:before,
+.dot-ha-font.disabled .b-font:before {
+  content: "\e606";
+  color: #ffffff;
+}
+.dot-e-font .b-font:before {
+  content: "\e606";
+  color: #ffffff;
+}
+.dot-e-font:hover .b-font:before,
+.dot-e-font:focus .b-font:before,
+.dot-e-font.hover .b-font:before {
+  content: "\e606";
+  color: #f4f4f4;
+}
+.dot-e-font.active .b-font:before {
+  content: "\e606";
+  color: #1a1a1a;
+}
+.dot-e-font:active .b-font:before {
+  content: "\e606";
+  color: #009de3;
+}
+.dot-e-font.native .b-font:before,
+.dot-e-font.disabled .b-font:before {
+  content: "\e606";
+  color: #ffffff;
+}
+.pull-right-font .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-font.native .b-font:before,
+.pull-right-font.disabled .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-h-font .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-h-font:hover .b-font:before,
+.pull-right-h-font:focus .b-font:before,
+.pull-right-h-font.hover .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-h-font.native .b-font:before,
+.pull-right-h-font.disabled .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-ha-font .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-ha-font:hover .b-font:before,
+.pull-right-ha-font:focus .b-font:before,
+.pull-right-ha-font.hover .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-ha-font:active .b-font:before,
+.pull-right-ha-font.active .b-font:before {
+  content: "\e607";
+  color: #009de3;
+}
+.pull-right-ha-font.native .b-font:before,
+.pull-right-ha-font.disabled .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-e-font .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-e-font:hover .b-font:before,
+.pull-right-e-font:focus .b-font:before,
+.pull-right-e-font.hover .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.pull-right-e-font.active .b-font:before {
+  content: "\e607";
+  color: #009de3;
+}
+.pull-right-e-font:active .b-font:before {
+  content: "\e607";
+  color: #009de3;
+}
+.pull-right-e-font.native .b-font:before,
+.pull-right-e-font.disabled .b-font:before {
+  content: "\e607";
+  color: #1a1a1a;
+}
+.copy-font .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-font.native .b-font:before,
+.copy-font.disabled .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-h-font .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-h-font:hover .b-font:before,
+.copy-h-font:focus .b-font:before,
+.copy-h-font.hover .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-h-font.native .b-font:before,
+.copy-h-font.disabled .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-ha-font .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-ha-font:hover .b-font:before,
+.copy-ha-font:focus .b-font:before,
+.copy-ha-font.hover .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-ha-font:active .b-font:before,
+.copy-ha-font.active .b-font:before {
+  content: "\e610";
+  color: #009de3;
+}
+.copy-ha-font.native .b-font:before,
+.copy-ha-font.disabled .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-e-font .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-e-font:hover .b-font:before,
+.copy-e-font:focus .b-font:before,
+.copy-e-font.hover .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.copy-e-font.active .b-font:before {
+  content: "\e610";
+  color: #009de3;
+}
+.copy-e-font:active .b-font:before {
+  content: "\e610";
+  color: #009de3;
+}
+.copy-e-font.native .b-font:before,
+.copy-e-font.disabled .b-font:before {
+  content: "\e610";
+  color: #1a1a1a;
+}
+.check-mark-font .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-font.native .b-font:before,
+.check-mark-font.disabled .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-h-font .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-h-font:hover .b-font:before,
+.check-mark-h-font:focus .b-font:before,
+.check-mark-h-font.hover .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-h-font.native .b-font:before,
+.check-mark-h-font.disabled .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-ha-font .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-ha-font:hover .b-font:before,
+.check-mark-ha-font:focus .b-font:before,
+.check-mark-ha-font.hover .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-ha-font:active .b-font:before,
+.check-mark-ha-font.active .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.check-mark-ha-font.native .b-font:before,
+.check-mark-ha-font.disabled .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-e-font .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-e-font:hover .b-font:before,
+.check-mark-e-font:focus .b-font:before,
+.check-mark-e-font.hover .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.check-mark-e-font.active .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.check-mark-e-font:active .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.check-mark-e-font.native .b-font:before,
+.check-mark-e-font.disabled .b-font:before {
+  content: "\e611";
+  color: #1a1a1a;
+}
+.dimension-from-font .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-font.native .b-font:before,
+.dimension-from-font.disabled .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-h-font .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-h-font:hover .b-font:before,
+.dimension-from-h-font:focus .b-font:before,
+.dimension-from-h-font.hover .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-h-font.native .b-font:before,
+.dimension-from-h-font.disabled .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-ha-font .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-ha-font:hover .b-font:before,
+.dimension-from-ha-font:focus .b-font:before,
+.dimension-from-ha-font.hover .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-ha-font:active .b-font:before,
+.dimension-from-ha-font.active .b-font:before {
+  content: "\e612";
+  color: #009de3;
+}
+.dimension-from-ha-font.native .b-font:before,
+.dimension-from-ha-font.disabled .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-e-font .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-e-font:hover .b-font:before,
+.dimension-from-e-font:focus .b-font:before,
+.dimension-from-e-font.hover .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.dimension-from-e-font.active .b-font:before {
+  content: "\e612";
+  color: #009de3;
+}
+.dimension-from-e-font:active .b-font:before {
+  content: "\e612";
+  color: #009de3;
+}
+.dimension-from-e-font.native .b-font:before,
+.dimension-from-e-font.disabled .b-font:before {
+  content: "\e612";
+  color: #1a1a1a;
+}
+.chart-type-font .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-font.native .b-font:before,
+.chart-type-font.disabled .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-h-font .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-h-font:hover .b-font:before,
+.chart-type-h-font:focus .b-font:before,
+.chart-type-h-font.hover .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-h-font.native .b-font:before,
+.chart-type-h-font.disabled .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-ha-font .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-ha-font:hover .b-font:before,
+.chart-type-ha-font:focus .b-font:before,
+.chart-type-ha-font.hover .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-ha-font:active .b-font:before,
+.chart-type-ha-font.active .b-font:before {
+  content: "\e613";
+  color: #009de3;
+}
+.chart-type-ha-font.native .b-font:before,
+.chart-type-ha-font.disabled .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-e-font .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-e-font:hover .b-font:before,
+.chart-type-e-font:focus .b-font:before,
+.chart-type-e-font.hover .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.chart-type-e-font.active .b-font:before {
+  content: "\e613";
+  color: #009de3;
+}
+.chart-type-e-font:active .b-font:before {
+  content: "\e613";
+  color: #009de3;
+}
+.chart-type-e-font.native .b-font:before,
+.chart-type-e-font.disabled .b-font:before {
+  content: "\e613";
+  color: #1a1a1a;
+}
+.style-set-font .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-font.native .b-font:before,
+.style-set-font.disabled .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-h-font .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-h-font:hover .b-font:before,
+.style-set-h-font:focus .b-font:before,
+.style-set-h-font.hover .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-h-font.native .b-font:before,
+.style-set-h-font.disabled .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-ha-font .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-ha-font:hover .b-font:before,
+.style-set-ha-font:focus .b-font:before,
+.style-set-ha-font.hover .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-ha-font:active .b-font:before,
+.style-set-ha-font.active .b-font:before {
+  content: "\e60c";
+  color: #009de3;
+}
+.style-set-ha-font.native .b-font:before,
+.style-set-ha-font.disabled .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-e-font .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-e-font:hover .b-font:before,
+.style-set-e-font:focus .b-font:before,
+.style-set-e-font.hover .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.style-set-e-font.active .b-font:before {
+  content: "\e60c";
+  color: #009de3;
+}
+.style-set-e-font:active .b-font:before {
+  content: "\e60c";
+  color: #009de3;
+}
+.style-set-e-font.native .b-font:before,
+.style-set-e-font.disabled .b-font:before {
+  content: "\e60c";
+  color: #1a1a1a;
+}
+.hyper-link-font .b-font:before {
+  content: "\e688";
+  color: #808080;
+}
+.hyper-link-font.native .b-font:before,
+.hyper-link-font.disabled .b-font:before {
+  content: "\e688";
+  color: #808080;
+}
+.filter-font .b-font:before {
+  content: "\e60f";
+  color: #808080;
+}
+.filter-font.native .b-font:before,
+.filter-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #808080;
+}
+.filter-h-font .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-h-font:hover .b-font:before,
+.filter-h-font:focus .b-font:before,
+.filter-h-font.hover .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-h-font.native .b-font:before,
+.filter-h-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-ha-font .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-ha-font:hover .b-font:before,
+.filter-ha-font:focus .b-font:before,
+.filter-ha-font.hover .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-ha-font:active .b-font:before,
+.filter-ha-font.active .b-font:before {
+  content: "\e60f";
+  color: #009de3;
+}
+.filter-ha-font.native .b-font:before,
+.filter-ha-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-e-font .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-e-font:hover .b-font:before,
+.filter-e-font:focus .b-font:before,
+.filter-e-font.hover .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.filter-e-font.active .b-font:before {
+  content: "\e60f";
+  color: #009de3;
+}
+.filter-e-font:active .b-font:before {
+  content: "\e60f";
+  color: #009de3;
+}
+.filter-e-font.native .b-font:before,
+.filter-e-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #1a1a1a;
+}
+.classify-font .b-font:before {
+  content: "\e694";
+  color: #009de3;
+}
+.classify-font.native .b-font:before,
+.classify-font.disabled .b-font:before {
+  content: "\e694";
+  color: #009de3;
+}
+.series-font .b-font:before {
+  content: "\e695";
+  color: #58cc7d;
+}
+.series-font.native .b-font:before,
+.series-font.disabled .b-font:before {
+  content: "\e695";
+  color: #58cc7d;
+}
+/**维度/指标 下拉列表图标字体 ~end~**/
+/** dashboard组件/控件 下拉列表图标字体 ~begin~**/
+.link-to-widget-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.link-to-widget-h-font:hover .b-font:before,
+.link-to-widget-h-font:focus .b-font:before,
+.link-to-widget-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.link-to-widget-h-font.native .b-font:before,
+.link-to-widget-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.link-to-detail-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.link-to-detail-h-font:hover .b-font:before,
+.link-to-detail-h-font:focus .b-font:before,
+.link-to-detail-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.link-to-detail-h-font.native .b-font:before,
+.link-to-detail-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.detail-setting-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.detail-setting-h-font:hover .b-font:before,
+.detail-setting-h-font:focus .b-font:before,
+.detail-setting-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.detail-setting-h-font.native .b-font:before,
+.detail-setting-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.export-to-excel-h-font .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.export-to-excel-h-font:hover .b-font:before,
+.export-to-excel-h-font:focus .b-font:before,
+.export-to-excel-h-font.hover .b-font:before {
+  content: "\e600";
+  color: #009de3;
+}
+.export-to-excel-h-font.native .b-font:before,
+.export-to-excel-h-font.disabled .b-font:before {
+  content: "\e600";
+  color: #808080;
+}
+.widget-copy-h-font .b-font:before {
+  content: "\e610";
+  color: #808080;
+}
+.widget-copy-h-font:hover .b-font:before,
+.widget-copy-h-font:focus .b-font:before,
+.widget-copy-h-font.hover .b-font:before {
+  content: "\e610";
+  color: #009de3;
+}
+.widget-copy-h-font.native .b-font:before,
+.widget-copy-h-font.disabled .b-font:before {
+  content: "\e610";
+  color: #808080;
+}
+.widget-delete-h-font .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.widget-delete-h-font:hover .b-font:before,
+.widget-delete-h-font:focus .b-font:before,
+.widget-delete-h-font.hover .b-font:before {
+  content: "\e605";
+  color: #009de3;
+}
+.widget-delete-h-font.native .b-font:before,
+.widget-delete-h-font.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+/** dashboard组件/控件 下拉列表图标字体 ~end~**/
+.tree-node-triangle-expand-font .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.tree-node-triangle-expand-font.native .b-font:before,
+.tree-node-triangle-expand-font.disabled .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.tree-node-triangle-collapse-font .b-font:before {
+  content: "\e607";
+  color: #808080;
+}
+.tree-node-triangle-collapse-font.native .b-font:before,
+.tree-node-triangle-collapse-font.disabled .b-font:before {
+  content: "\e607";
+  color: #808080;
+}
+.row-pre-page-h-font .b-font:before {
+  content: "\e6be";
+  color: #1a1a1a;
+}
+.row-pre-page-h-font:hover .b-font:before,
+.row-pre-page-h-font:focus .b-font:before,
+.row-pre-page-h-font.hover .b-font:before {
+  content: "\e6be";
+  color: #1a1a1a;
+}
+.row-pre-page-h-font.native .b-font:before,
+.row-pre-page-h-font.disabled .b-font:before {
+  content: "\e6be";
+  color: #1a1a1a;
+}
+.row-next-page-h-font .b-font:before {
+  content: "\e6bd";
+  color: #1a1a1a;
+}
+.row-next-page-h-font:hover .b-font:before,
+.row-next-page-h-font:focus .b-font:before,
+.row-next-page-h-font.hover .b-font:before {
+  content: "\e6bd";
+  color: #1a1a1a;
+}
+.row-next-page-h-font.native .b-font:before,
+.row-next-page-h-font.disabled .b-font:before {
+  content: "\e6bd";
+  color: #1a1a1a;
+}
+.column-pre-page-h-font .b-font:before {
+  content: "\e6bc";
+  color: #1a1a1a;
+}
+.column-pre-page-h-font:hover .b-font:before,
+.column-pre-page-h-font:focus .b-font:before,
+.column-pre-page-h-font.hover .b-font:before {
+  content: "\e6bc";
+  color: #1a1a1a;
+}
+.column-pre-page-h-font.native .b-font:before,
+.column-pre-page-h-font.disabled .b-font:before {
+  content: "\e6bc";
+  color: #1a1a1a;
+}
+.column-next-page-h-font .b-font:before {
+  content: "\e6bb";
+  color: #1a1a1a;
+}
+.column-next-page-h-font:hover .b-font:before,
+.column-next-page-h-font:focus .b-font:before,
+.column-next-page-h-font.hover .b-font:before {
+  content: "\e6bb";
+  color: #1a1a1a;
+}
+.column-next-page-h-font.native .b-font:before,
+.column-next-page-h-font.disabled .b-font:before {
+  content: "\e6bb";
+  color: #1a1a1a;
+}
+.trigger-triangle-font .b-font:before {
+  content: "\e66a";
+  color: #808080;
+}
+.trigger-triangle-font:hover .b-font:before,
+.trigger-triangle-font:focus .b-font:before,
+.trigger-triangle-font.hover .b-font:before {
+  content: "\e66a";
+  color: #808080;
+}
+.trigger-triangle-font:active .b-font:before,
+.trigger-triangle-font.active .b-font:before {
+  content: "\e66a";
+  color: #009de3;
+}
+.trigger-triangle-font.native .b-font:before,
+.trigger-triangle-font.disabled .b-font:before {
+  content: "\e66a";
+  color: #808080;
+}
+.widget-date-next-h-font .b-font:before {
+  content: "\e62f";
+  color: #808080;
+}
+.widget-date-next-h-font:hover .b-font:before,
+.widget-date-next-h-font:focus .b-font:before,
+.widget-date-next-h-font.hover .b-font:before {
+  content: "\e62f";
+  color: #808080;
+}
+.widget-date-next-h-font.native .b-font:before,
+.widget-date-next-h-font.disabled .b-font:before {
+  content: "\e62f";
+  color: #808080;
+}
+.widget-date-pre-h-font .b-font:before {
+  content: "\e62e";
+  color: #808080;
+}
+.widget-date-pre-h-font:hover .b-font:before,
+.widget-date-pre-h-font:focus .b-font:before,
+.widget-date-pre-h-font.hover .b-font:before {
+  content: "\e62e";
+  color: #808080;
+}
+.widget-date-pre-h-font.native .b-font:before,
+.widget-date-pre-h-font.disabled .b-font:before {
+  content: "\e62e";
+  color: #808080;
+}
+.widget-date-h-change-font .b-font:before {
+  content: "\e660";
+  color: #808080;
+}
+.widget-date-h-change-font:hover .b-font:before,
+.widget-date-h-change-font:focus .b-font:before,
+.widget-date-h-change-font.hover .b-font:before {
+  content: "\e660";
+  color: #808080;
+}
+.widget-date-h-change-font.native .b-font:before,
+.widget-date-h-change-font.disabled .b-font:before {
+  content: "\e660";
+  color: #808080;
+}
+.pull-down-font .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-font.native .b-font:before,
+.pull-down-font.disabled .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-h-font .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-h-font:hover .b-font:before,
+.pull-down-h-font:focus .b-font:before,
+.pull-down-h-font.hover .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-h-font.native .b-font:before,
+.pull-down-h-font.disabled .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-ha-font .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-ha-font:hover .b-font:before,
+.pull-down-ha-font:focus .b-font:before,
+.pull-down-ha-font.hover .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.pull-down-ha-font:active .b-font:before,
+.pull-down-ha-font.active .b-font:before {
+  content: "\e608";
+  color: #009de3;
+}
+.pull-down-ha-font.native .b-font:before,
+.pull-down-ha-font.disabled .b-font:before {
+  content: "\e608";
+  color: #808080;
+}
+.delete-field-font .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-font.native .b-font:before,
+.delete-field-font.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-h-font .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-h-font:hover .b-font:before,
+.delete-field-h-font:focus .b-font:before,
+.delete-field-h-font.hover .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-h-font.native .b-font:before,
+.delete-field-h-font.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-ha-font .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-ha-font:hover .b-font:before,
+.delete-field-ha-font:focus .b-font:before,
+.delete-field-ha-font.hover .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-field-ha-font:active .b-font:before,
+.delete-field-ha-font.active .b-font:before {
+  content: "\e605";
+  color: #009de3;
+}
+.delete-field-ha-font.native .b-font:before,
+.delete-field-ha-font.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.toolbar-save-font .b-font:before {
+  content: "\e617";
+  color: #808080;
+}
+.toolbar-save-font:hover .b-font:before,
+.toolbar-save-font:focus .b-font:before,
+.toolbar-save-font.hover .b-font:before {
+  content: "\e617";
+  color: #808080;
+}
+.toolbar-save-font.native .b-font:before,
+.toolbar-save-font.disabled .b-font:before {
+  content: "\e617";
+  color: #808080;
+}
+.toolbar-undo-font .b-font:before {
+  content: "\e619";
+  color: #808080;
+}
+.toolbar-undo-font:hover .b-font:before,
+.toolbar-undo-font:focus .b-font:before,
+.toolbar-undo-font.hover .b-font:before {
+  content: "\e619";
+  color: #808080;
+}
+.toolbar-undo-font.native .b-font:before,
+.toolbar-undo-font.disabled .b-font:before {
+  content: "\e619";
+  color: #808080;
+}
+.toolbar-redo-font .b-font:before {
+  content: "\e625";
+  color: #808080;
+}
+.toolbar-redo-font:hover .b-font:before,
+.toolbar-redo-font:focus .b-font:before,
+.toolbar-redo-font.hover .b-font:before {
+  content: "\e625";
+  color: #808080;
+}
+.toolbar-redo-font.native .b-font:before,
+.toolbar-redo-font.disabled .b-font:before {
+  content: "\e625";
+  color: #808080;
+}
+.toolbar-edit-font .b-font:before {
+  content: "\e631";
+  color: #808080;
+}
+.toolbar-edit-font:hover .b-font:before,
+.toolbar-edit-font:focus .b-font:before,
+.toolbar-edit-font.hover .b-font:before {
+  content: "\e631";
+  color: #808080;
+}
+.toolbar-edit-font.native .b-font:before,
+.toolbar-edit-font.disabled .b-font:before {
+  content: "\e631";
+  color: #808080;
+}
+.toolbar-preview-font .b-font:before {
+  content: "\e65f";
+  color: #808080;
+}
+.toolbar-preview-font:hover .b-font:before,
+.toolbar-preview-font:focus .b-font:before,
+.toolbar-preview-font.hover .b-font:before {
+  content: "\e65f";
+  color: #808080;
+}
+.toolbar-preview-font.native .b-font:before,
+.toolbar-preview-font.disabled .b-font:before {
+  content: "\e65f";
+  color: #808080;
+}
+.chart-table-font .b-font:before {
+  content: "\e60e";
+  color: #808080;
+}
+.chart-table-font:hover .b-font:before,
+.chart-table-font:focus .b-font:before,
+.chart-table-font.hover .b-font:before {
+  content: "\e60e";
+  color: #808080;
+}
+.chart-table-font:active .b-font:before,
+.chart-table-font.active .b-font:before {
+  content: "\e60e";
+  color: #009de3;
+}
+.chart-table-font.native .b-font:before,
+.chart-table-font.disabled .b-font:before {
+  content: "\e60e";
+  color: #808080;
+}
+.chart-axis-font .b-font:before {
+  content: "\e626";
+  color: #808080;
+}
+.chart-axis-font:hover .b-font:before,
+.chart-axis-font:focus .b-font:before,
+.chart-axis-font.hover .b-font:before {
+  content: "\e626";
+  color: #808080;
+}
+.chart-axis-font:active .b-font:before,
+.chart-axis-font.active .b-font:before {
+  content: "\e626";
+  color: #009de3;
+}
+.chart-axis-font.native .b-font:before,
+.chart-axis-font.disabled .b-font:before {
+  content: "\e626";
+  color: #808080;
+}
+.chart-bar-font .b-font:before {
+  content: "\e620";
+  color: #808080;
+}
+.chart-bar-font:hover .b-font:before,
+.chart-bar-font:focus .b-font:before,
+.chart-bar-font.hover .b-font:before {
+  content: "\e620";
+  color: #808080;
+}
+.chart-bar-font:active .b-font:before,
+.chart-bar-font.active .b-font:before {
+  content: "\e620";
+  color: #009de3;
+}
+.chart-bar-font.native .b-font:before,
+.chart-bar-font.disabled .b-font:before {
+  content: "\e620";
+  color: #808080;
+}
+.chart-accumulate-bar-font .b-font:before {
+  content: "\e60a";
+  color: #808080;
+}
+.chart-accumulate-bar-font:hover .b-font:before,
+.chart-accumulate-bar-font:focus .b-font:before,
+.chart-accumulate-bar-font.hover .b-font:before {
+  content: "\e60a";
+  color: #808080;
+}
+.chart-accumulate-bar-font:active .b-font:before,
+.chart-accumulate-bar-font.active .b-font:before {
+  content: "\e60a";
+  color: #009de3;
+}
+.chart-accumulate-bar-font.native .b-font:before,
+.chart-accumulate-bar-font.disabled .b-font:before {
+  content: "\e60a";
+  color: #808080;
+}
+.chart-pie-font .b-font:before {
+  content: "\e618";
+  color: #808080;
+}
+.chart-pie-font:hover .b-font:before,
+.chart-pie-font:focus .b-font:before,
+.chart-pie-font.hover .b-font:before {
+  content: "\e618";
+  color: #808080;
+}
+.chart-pie-font:active .b-font:before,
+.chart-pie-font.active .b-font:before {
+  content: "\e618";
+  color: #009de3;
+}
+.chart-pie-font.native .b-font:before,
+.chart-pie-font.disabled .b-font:before {
+  content: "\e618";
+  color: #808080;
+}
+.chart-map-font .b-font:before {
+  content: "\e62c";
+  color: #808080;
+}
+.chart-map-font:hover .b-font:before,
+.chart-map-font:focus .b-font:before,
+.chart-map-font.hover .b-font:before {
+  content: "\e62c";
+  color: #808080;
+}
+.chart-map-font:active .b-font:before,
+.chart-map-font.active .b-font:before {
+  content: "\e62c";
+  color: #009de3;
+}
+.chart-map-font.native .b-font:before,
+.chart-map-font.disabled .b-font:before {
+  content: "\e62c";
+  color: #808080;
+}
+.chart-dashboard-font .b-font:before {
+  content: "\e623";
+  color: #808080;
+}
+.chart-dashboard-font:hover .b-font:before,
+.chart-dashboard-font:focus .b-font:before,
+.chart-dashboard-font.hover .b-font:before {
+  content: "\e623";
+  color: #808080;
+}
+.chart-dashboard-font:active .b-font:before,
+.chart-dashboard-font.active .b-font:before {
+  content: "\e623";
+  color: #009de3;
+}
+.chart-dashboard-font.native .b-font:before,
+.chart-dashboard-font.disabled .b-font:before {
+  content: "\e623";
+  color: #808080;
+}
+.chart-doughnut-font .b-font:before {
+  content: "\e624";
+  color: #808080;
+}
+.chart-doughnut-font:hover .b-font:before,
+.chart-doughnut-font:focus .b-font:before,
+.chart-doughnut-font.hover .b-font:before {
+  content: "\e624";
+  color: #808080;
+}
+.chart-doughnut-font:active .b-font:before,
+.chart-doughnut-font.active .b-font:before {
+  content: "\e624";
+  color: #009de3;
+}
+.chart-doughnut-font.native .b-font:before,
+.chart-doughnut-font.disabled .b-font:before {
+  content: "\e624";
+  color: #808080;
+}
+.chart-detail-font .b-font:before {
+  content: "\e615";
+  color: #808080;
+}
+.chart-detail-font:hover .b-font:before,
+.chart-detail-font:focus .b-font:before,
+.chart-detail-font.hover .b-font:before {
+  content: "\e615";
+  color: #808080;
+}
+.chart-detail-font:active .b-font:before,
+.chart-detail-font.active .b-font:before {
+  content: "\e615";
+  color: #009de3;
+}
+.chart-detail-font.native .b-font:before,
+.chart-detail-font.disabled .b-font:before {
+  content: "\e615";
+  color: #808080;
+}
+.chart-more-font .b-font:before {
+  content: "\e60d";
+  color: #808080;
+}
+.chart-more-font:hover .b-font:before,
+.chart-more-font:focus .b-font:before,
+.chart-more-font.hover .b-font:before {
+  content: "\e60d";
+  color: #808080;
+}
+.chart-more-font:active .b-font:before,
+.chart-more-font.active .b-font:before {
+  content: "\e60d";
+  color: #009de3;
+}
+.chart-more-font.native .b-font:before,
+.chart-more-font.disabled .b-font:before {
+  content: "\e60d";
+  color: #808080;
+}
+.chart-bubble-font .b-font:before {
+  content: "\e62a";
+  color: #808080;
+}
+.chart-bubble-font:hover .b-font:before,
+.chart-bubble-font:focus .b-font:before,
+.chart-bubble-font.hover .b-font:before {
+  content: "\e62a";
+  color: #808080;
+}
+.chart-bubble-font:active .b-font:before,
+.chart-bubble-font.active .b-font:before {
+  content: "\e62a";
+  color: #009de3;
+}
+.chart-bubble-font.native .b-font:before,
+.chart-bubble-font.disabled .b-font:before {
+  content: "\e62a";
+  color: #808080;
+}
+.chart-scatter-font .b-font:before {
+  content: "\e61d";
+  color: #808080;
+}
+.chart-scatter-font:hover .b-font:before,
+.chart-scatter-font:focus .b-font:before,
+.chart-scatter-font.hover .b-font:before {
+  content: "\e61d";
+  color: #808080;
+}
+.chart-scatter-font:active .b-font:before,
+.chart-scatter-font.active .b-font:before {
+  content: "\e61d";
+  color: #009de3;
+}
+.chart-scatter-font.native .b-font:before,
+.chart-scatter-font.disabled .b-font:before {
+  content: "\e61d";
+  color: #808080;
+}
+.chart-radar-font .b-font:before {
+  content: "\e614";
+  color: #808080;
+}
+.chart-radar-font:hover .b-font:before,
+.chart-radar-font:focus .b-font:before,
+.chart-radar-font.hover .b-font:before {
+  content: "\e614";
+  color: #808080;
+}
+.chart-radar-font:active .b-font:before,
+.chart-radar-font.active .b-font:before {
+  content: "\e614";
+  color: #009de3;
+}
+.chart-radar-font.native .b-font:before,
+.chart-radar-font.disabled .b-font:before {
+  content: "\e614";
+  color: #808080;
+}
+.chart-content-font .b-font:before {
+  content: "\e621";
+  color: #808080;
+}
+.chart-content-font:hover .b-font:before,
+.chart-content-font:focus .b-font:before,
+.chart-content-font.hover .b-font:before {
+  content: "\e621";
+  color: #808080;
+}
+.chart-content-font:active .b-font:before,
+.chart-content-font.active .b-font:before {
+  content: "\e621";
+  color: #009de3;
+}
+.chart-content-font.native .b-font:before,
+.chart-content-font.disabled .b-font:before {
+  content: "\e621";
+  color: #808080;
+}
+.chart-image-font .b-font:before {
+  content: "\e68d";
+  color: #808080;
+}
+.chart-image-font:hover .b-font:before,
+.chart-image-font:focus .b-font:before,
+.chart-image-font.hover .b-font:before {
+  content: "\e68d";
+  color: #808080;
+}
+.chart-image-font:active .b-font:before,
+.chart-image-font.active .b-font:before {
+  content: "\e68d";
+  color: #009de3;
+}
+.chart-image-font.native .b-font:before,
+.chart-image-font.disabled .b-font:before {
+  content: "\e68d";
+  color: #808080;
+}
+.chart-web-font .b-font:before {
+  content: "\e68c";
+  color: #808080;
+}
+.chart-web-font:hover .b-font:before,
+.chart-web-font:focus .b-font:before,
+.chart-web-font.hover .b-font:before {
+  content: "\e68c";
+  color: #808080;
+}
+.chart-web-font:active .b-font:before,
+.chart-web-font.active .b-font:before {
+  content: "\e68c";
+  color: #009de3;
+}
+.chart-web-font.native .b-font:before,
+.chart-web-font.disabled .b-font:before {
+  content: "\e68c";
+  color: #808080;
+}
+.chart-string-font .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-string-font:hover .b-font:before,
+.chart-string-font:focus .b-font:before,
+.chart-string-font.hover .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-string-font:active .b-font:before,
+.chart-string-font.active .b-font:before {
+  content: "\e622";
+  color: #009de3;
+}
+.chart-string-font.native .b-font:before,
+.chart-string-font.disabled .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-number-font .b-font:before {
+  content: "\e61f";
+  color: #808080;
+}
+.chart-number-font:hover .b-font:before,
+.chart-number-font:focus .b-font:before,
+.chart-number-font.hover .b-font:before {
+  content: "\e61f";
+  color: #808080;
+}
+.chart-number-font:active .b-font:before,
+.chart-number-font.active .b-font:before {
+  content: "\e61f";
+  color: #009de3;
+}
+.chart-number-font.native .b-font:before,
+.chart-number-font.disabled .b-font:before {
+  content: "\e61f";
+  color: #808080;
+}
+.chart-tree-font .b-font:before {
+  content: "\e61e";
+  color: #808080;
+}
+.chart-tree-font:hover .b-font:before,
+.chart-tree-font:focus .b-font:before,
+.chart-tree-font.hover .b-font:before {
+  content: "\e61e";
+  color: #808080;
+}
+.chart-tree-font:active .b-font:before,
+.chart-tree-font.active .b-font:before {
+  content: "\e61e";
+  color: #009de3;
+}
+.chart-tree-font.native .b-font:before,
+.chart-tree-font.disabled .b-font:before {
+  content: "\e61e";
+  color: #808080;
+}
+.chart-date-font .b-font:before {
+  content: "\e61b";
+  color: #808080;
+}
+.chart-date-font:hover .b-font:before,
+.chart-date-font:focus .b-font:before,
+.chart-date-font.hover .b-font:before {
+  content: "\e61b";
+  color: #808080;
+}
+.chart-date-font:active .b-font:before,
+.chart-date-font.active .b-font:before {
+  content: "\e61b";
+  color: #009de3;
+}
+.chart-date-font.native .b-font:before,
+.chart-date-font.disabled .b-font:before {
+  content: "\e61b";
+  color: #808080;
+}
+.chart-year-font .b-font:before {
+  content: "\e628";
+  color: #808080;
+}
+.chart-year-font:hover .b-font:before,
+.chart-year-font:focus .b-font:before,
+.chart-year-font.hover .b-font:before {
+  content: "\e628";
+  color: #808080;
+}
+.chart-year-font:active .b-font:before,
+.chart-year-font.active .b-font:before {
+  content: "\e628";
+  color: #009de3;
+}
+.chart-year-font.native .b-font:before,
+.chart-year-font.disabled .b-font:before {
+  content: "\e628";
+  color: #808080;
+}
+.chart-month-font .b-font:before {
+  content: "\e627";
+  color: #808080;
+}
+.chart-month-font:hover .b-font:before,
+.chart-month-font:focus .b-font:before,
+.chart-month-font.hover .b-font:before {
+  content: "\e627";
+  color: #808080;
+}
+.chart-month-font:active .b-font:before,
+.chart-month-font.active .b-font:before {
+  content: "\e627";
+  color: #009de3;
+}
+.chart-month-font.native .b-font:before,
+.chart-month-font.disabled .b-font:before {
+  content: "\e627";
+  color: #808080;
+}
+.chart-quarter-font .b-font:before {
+  content: "\e629";
+  color: #808080;
+}
+.chart-quarter-font:hover .b-font:before,
+.chart-quarter-font:focus .b-font:before,
+.chart-quarter-font.hover .b-font:before {
+  content: "\e629";
+  color: #808080;
+}
+.chart-quarter-font:active .b-font:before,
+.chart-quarter-font.active .b-font:before {
+  content: "\e629";
+  color: #009de3;
+}
+.chart-quarter-font.native .b-font:before,
+.chart-quarter-font.disabled .b-font:before {
+  content: "\e629";
+  color: #808080;
+}
+.chart-ymd-font .b-font:before {
+  content: "\e61c";
+  color: #808080;
+}
+.chart-ymd-font:hover .b-font:before,
+.chart-ymd-font:focus .b-font:before,
+.chart-ymd-font.hover .b-font:before {
+  content: "\e61c";
+  color: #808080;
+}
+.chart-ymd-font:active .b-font:before,
+.chart-ymd-font.active .b-font:before {
+  content: "\e61c";
+  color: #009de3;
+}
+.chart-ymd-font.native .b-font:before,
+.chart-ymd-font.disabled .b-font:before {
+  content: "\e61c";
+  color: #808080;
+}
+.chart-date-range-font .b-font:before {
+  content: "\e616";
+  color: #808080;
+}
+.chart-date-range-font:hover .b-font:before,
+.chart-date-range-font:focus .b-font:before,
+.chart-date-range-font.hover .b-font:before {
+  content: "\e616";
+  color: #808080;
+}
+.chart-date-range-font:active .b-font:before,
+.chart-date-range-font.active .b-font:before {
+  content: "\e616";
+  color: #009de3;
+}
+.chart-date-range-font.native .b-font:before,
+.chart-date-range-font.disabled .b-font:before {
+  content: "\e616";
+  color: #808080;
+}
+.chart-general-query-font .b-font:before {
+  content: "\e62b";
+  color: #808080;
+}
+.chart-general-query-font:hover .b-font:before,
+.chart-general-query-font:focus .b-font:before,
+.chart-general-query-font.hover .b-font:before {
+  content: "\e62b";
+  color: #808080;
+}
+.chart-general-query-font:active .b-font:before,
+.chart-general-query-font.active .b-font:before {
+  content: "\e62b";
+  color: #009de3;
+}
+.chart-general-query-font.native .b-font:before,
+.chart-general-query-font.disabled .b-font:before {
+  content: "\e62b";
+  color: #808080;
+}
+.chart-query-font .b-font:before {
+  content: "\e609";
+  color: #808080;
+}
+.chart-query-font:hover .b-font:before,
+.chart-query-font:focus .b-font:before,
+.chart-query-font.hover .b-font:before {
+  content: "\e609";
+  color: #808080;
+}
+.chart-query-font:active .b-font:before,
+.chart-query-font.active .b-font:before {
+  content: "\e609";
+  color: #009de3;
+}
+.chart-query-font.native .b-font:before,
+.chart-query-font.disabled .b-font:before {
+  content: "\e609";
+  color: #808080;
+}
+.chart-reset-font .b-font:before {
+  content: "\e61a";
+  color: #808080;
+}
+.chart-reset-font:hover .b-font:before,
+.chart-reset-font:focus .b-font:before,
+.chart-reset-font.hover .b-font:before {
+  content: "\e61a";
+  color: #808080;
+}
+.chart-reset-font:active .b-font:before,
+.chart-reset-font.active .b-font:before {
+  content: "\e61a";
+  color: #009de3;
+}
+.chart-reset-font.native .b-font:before,
+.chart-reset-font.disabled .b-font:before {
+  content: "\e61a";
+  color: #808080;
+}
+.chart-textarea-font .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-textarea-font:hover .b-font:before,
+.chart-textarea-font:focus .b-font:before,
+.chart-textarea-font.hover .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-textarea-font:active .b-font:before,
+.chart-textarea-font.active .b-font:before {
+  content: "\e622";
+  color: #009de3;
+}
+.chart-textarea-font.native .b-font:before,
+.chart-textarea-font.disabled .b-font:before {
+  content: "\e622";
+  color: #808080;
+}
+.chart-reuse-font .b-font:before {
+  content: "\e60b";
+  color: #808080;
+}
+.chart-reuse-font:hover .b-font:before,
+.chart-reuse-font:focus .b-font:before,
+.chart-reuse-font.hover .b-font:before {
+  content: "\e60b";
+  color: #808080;
+}
+.chart-reuse-font:active .b-font:before,
+.chart-reuse-font.active .b-font:before {
+  content: "\e60b";
+  color: #009de3;
+}
+.chart-reuse-font.native .b-font:before,
+.chart-reuse-font.disabled .b-font:before {
+  content: "\e60b";
+  color: #808080;
+}
+.chart-date-normal-font .b-font:before {
+  content: "\e61b";
+  color: #808080;
+}
+.chart-date-normal-font.native .b-font:before,
+.chart-date-normal-font.disabled .b-font:before {
+  content: "\e61b";
+  color: #808080;
+}
+.less-font .b-font:before {
+  content: "\e633";
+  color: #808080;
+}
+.less-font:hover .b-font:before,
+.less-font:focus .b-font:before,
+.less-font.hover .b-font:before {
+  content: "\e633";
+  color: #808080;
+}
+.less-font:active .b-font:before,
+.less-font.active .b-font:before {
+  content: "\e633";
+  color: #009de3;
+}
+.less-font.native .b-font:before,
+.less-font.disabled .b-font:before {
+  content: "\e633";
+  color: #808080;
+}
+.less-equal-font .b-font:before {
+  content: "\e636";
+  color: #808080;
+}
+.less-equal-font:hover .b-font:before,
+.less-equal-font:focus .b-font:before,
+.less-equal-font.hover .b-font:before {
+  content: "\e636";
+  color: #808080;
+}
+.less-equal-font:active .b-font:before,
+.less-equal-font.active .b-font:before {
+  content: "\e636";
+  color: #009de3;
+}
+.less-equal-font.native .b-font:before,
+.less-equal-font.disabled .b-font:before {
+  content: "\e636";
+  color: #808080;
+}
+.check-font .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.check-font.native .b-font:before,
+.check-font.disabled .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.move2group-add-font .b-font:before {
+  content: "\e649";
+  color: #009de3;
+}
+.move2group-add-font.native .b-font:before,
+.move2group-add-font.disabled .b-font:before {
+  content: "\e649";
+  color: #009de3;
+}
+.select-data-field-calc-font .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.select-data-field-calc-font:hover .b-font:before,
+.select-data-field-calc-font:focus .b-font:before,
+.select-data-field-calc-font.hover .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.select-data-field-calc-font:active .b-font:before,
+.select-data-field-calc-font.active .b-font:before {
+  content: "\e6a3";
+  color: #ffffff;
+}
+.select-data-field-calc-font.native .b-font:before,
+.select-data-field-calc-font.disabled .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.select-data-field-string-font .b-font:before {
+  content: "\e642";
+  color: #1a1a1a;
+}
+.select-data-field-string-font:hover .b-font:before,
+.select-data-field-string-font:focus .b-font:before,
+.select-data-field-string-font.hover .b-font:before {
+  content: "\e642";
+  color: #1a1a1a;
+}
+.select-data-field-string-font:active .b-font:before,
+.select-data-field-string-font.active .b-font:before {
+  content: "\e642";
+  color: #ffffff;
+}
+.select-data-field-string-font.native .b-font:before,
+.select-data-field-string-font.disabled .b-font:before {
+  content: "\e642";
+  color: #1a1a1a;
+}
+.select-data-field-number-font .b-font:before {
+  content: "\e641";
+  color: #1a1a1a;
+}
+.select-data-field-number-font:hover .b-font:before,
+.select-data-field-number-font:focus .b-font:before,
+.select-data-field-number-font.hover .b-font:before {
+  content: "\e641";
+  color: #1a1a1a;
+}
+.select-data-field-number-font:active .b-font:before,
+.select-data-field-number-font.active .b-font:before {
+  content: "\e641";
+  color: #ffffff;
+}
+.select-data-field-number-font.native .b-font:before,
+.select-data-field-number-font.disabled .b-font:before {
+  content: "\e641";
+  color: #1a1a1a;
+}
+.select-data-field-date-font .b-font:before {
+  content: "\e640";
+  color: #1a1a1a;
+}
+.select-data-field-date-font:hover .b-font:before,
+.select-data-field-date-font:focus .b-font:before,
+.select-data-field-date-font.hover .b-font:before {
+  content: "\e640";
+  color: #1a1a1a;
+}
+.select-data-field-date-font:active .b-font:before,
+.select-data-field-date-font.active .b-font:before {
+  content: "\e640";
+  color: #ffffff;
+}
+.select-data-field-date-font.native .b-font:before,
+.select-data-field-date-font.disabled .b-font:before {
+  content: "\e640";
+  color: #1a1a1a;
+}
+.select-data-field-string-group-font .b-font:before {
+  content: "\e642";
+  color: #808080;
+}
+.select-data-field-string-group-font.native .b-font:before,
+.select-data-field-string-group-font.disabled .b-font:before {
+  content: "\e642";
+  color: #808080;
+}
+.select-data-field-number-group-font .b-font:before {
+  content: "\e641";
+  color: #808080;
+}
+.select-data-field-number-group-font.native .b-font:before,
+.select-data-field-number-group-font.disabled .b-font:before {
+  content: "\e641";
+  color: #808080;
+}
+.select-data-field-date-group-font .b-font:before {
+  content: "\e640";
+  color: #808080;
+}
+.select-data-field-date-group-font.native .b-font:before,
+.select-data-field-date-group-font.disabled .b-font:before {
+  content: "\e640";
+  color: #808080;
+}
+.select-data-preview-font .b-font:before {
+  content: "\e65f";
+  color: #808080;
+}
+.select-data-preview-font:hover .b-font:before,
+.select-data-preview-font:focus .b-font:before,
+.select-data-preview-font.hover .b-font:before {
+  content: "\e65f";
+  color: #009de3;
+}
+.select-data-preview-font:active .b-font:before,
+.select-data-preview-font.active .b-font:before {
+  content: "\e65f";
+  color: #009de3;
+}
+.select-data-preview-font.native .b-font:before,
+.select-data-preview-font.disabled .b-font:before {
+  content: "\e65f";
+  color: #808080;
+}
+.detail-dimension-set-font .b-font:before {
+  content: "\e678";
+  color: #808080;
+}
+.detail-dimension-set-font:hover .b-font:before,
+.detail-dimension-set-font:focus .b-font:before,
+.detail-dimension-set-font.hover .b-font:before {
+  content: "\e678";
+  color: #808080;
+}
+.detail-dimension-set-font.native .b-font:before,
+.detail-dimension-set-font.disabled .b-font:before {
+  content: "\e678";
+  color: #808080;
+}
+.detail-real-data-warning-font .b-font:before {
+  content: "\e64e";
+  color: #f07d0a;
+}
+.detail-real-data-warning-font:hover .b-font:before,
+.detail-real-data-warning-font:focus .b-font:before,
+.detail-real-data-warning-font.hover .b-font:before {
+  content: "\e64e";
+  color: #f07d0a;
+}
+.detail-real-data-warning-font.native .b-font:before,
+.detail-real-data-warning-font.disabled .b-font:before {
+  content: "\e64e";
+  color: #f07d0a;
+}
+.select-group-field-string-font .b-font:before {
+  content: "\e642";
+  color: #009de3;
+}
+.select-group-field-string-font:hover .b-font:before,
+.select-group-field-string-font:focus .b-font:before,
+.select-group-field-string-font.hover .b-font:before {
+  content: "\e642";
+  color: #009de3;
+}
+.select-group-field-string-font:active .b-font:before,
+.select-group-field-string-font.active .b-font:before {
+  content: "\e642";
+  color: #009de3;
+}
+.select-group-field-string-font.native .b-font:before,
+.select-group-field-string-font.disabled .b-font:before {
+  content: "\e642";
+  color: #009de3;
+}
+.select-group-field-number-font .b-font:before {
+  content: "\e641";
+  color: #009de3;
+}
+.select-group-field-number-font:hover .b-font:before,
+.select-group-field-number-font:focus .b-font:before,
+.select-group-field-number-font.hover .b-font:before {
+  content: "\e641";
+  color: #009de3;
+}
+.select-group-field-number-font:active .b-font:before,
+.select-group-field-number-font.active .b-font:before {
+  content: "\e641";
+  color: #009de3;
+}
+.select-group-field-number-font.native .b-font:before,
+.select-group-field-number-font.disabled .b-font:before {
+  content: "\e641";
+  color: #009de3;
+}
+.select-group-field-date-font .b-font:before {
+  content: "\e640";
+  color: #009de3;
+}
+.select-group-field-date-font:hover .b-font:before,
+.select-group-field-date-font:focus .b-font:before,
+.select-group-field-date-font.hover .b-font:before {
+  content: "\e640";
+  color: #009de3;
+}
+.select-group-field-date-font:active .b-font:before,
+.select-group-field-date-font.active .b-font:before {
+  content: "\e640";
+  color: #009de3;
+}
+.select-group-field-date-font.native .b-font:before,
+.select-group-field-date-font.disabled .b-font:before {
+  content: "\e640";
+  color: #009de3;
+}
+.dashboard-widget-combo-detail-set-font .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.dashboard-widget-combo-detail-set-font:hover .b-font:before,
+.dashboard-widget-combo-detail-set-font:focus .b-font:before,
+.dashboard-widget-combo-detail-set-font.hover .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.dashboard-widget-combo-detail-set-font.native .b-font:before,
+.dashboard-widget-combo-detail-set-font.disabled .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.group-add-font .b-font:before {
+  content: "\e649";
+  color: #808080;
+}
+.group-add-font.native .b-font:before,
+.group-add-font.disabled .b-font:before {
+  content: "\e649";
+  color: #808080;
+}
+.sortable-font .b-font:before {
+  content: "\e63b";
+  color: #808080;
+}
+.sortable-font.native .b-font:before,
+.sortable-font.disabled .b-font:before {
+  content: "\e63b";
+  color: #808080;
+}
+.text-bold-font .b-font:before {
+  content: "\e64d";
+  color: #1a1a1a;
+}
+.text-bold-font.native .b-font:before,
+.text-bold-font.disabled .b-font:before {
+  content: "\e64d";
+  color: #1a1a1a;
+}
+.text-italic-font .b-font:before {
+  content: "\e656";
+  color: #1a1a1a;
+}
+.text-italic-font.native .b-font:before,
+.text-italic-font.disabled .b-font:before {
+  content: "\e656";
+  color: #1a1a1a;
+}
+.text-underline-font .b-font:before {
+  content: "\e650";
+  color: #1a1a1a;
+}
+.text-underline-font.native .b-font:before,
+.text-underline-font.disabled .b-font:before {
+  content: "\e650";
+  color: #1a1a1a;
+}
+.text-color-font .b-font:before {
+  content: "\e69c";
+  color: #1a1a1a;
+}
+.text-color-font.native .b-font:before,
+.text-color-font.disabled .b-font:before {
+  content: "\e69c";
+  color: #1a1a1a;
+}
+.text-background-font .b-font:before {
+  content: "\e696";
+  color: #1a1a1a;
+}
+.text-background-font.native .b-font:before,
+.text-background-font.disabled .b-font:before {
+  content: "\e696";
+  color: #1a1a1a;
+}
+.text-color-underline-font .b-font:before {
+  content: "\e69d";
+  color: "";
+}
+.text-color-underline-font.native .b-font:before,
+.text-color-underline-font.disabled .b-font:before {
+  content: "\e69d";
+  color: "";
+}
+.text-align-left-font .b-font:before {
+  content: "\e654";
+  color: #1a1a1a;
+}
+.text-align-left-font.native .b-font:before,
+.text-align-left-font.disabled .b-font:before {
+  content: "\e654";
+  color: #1a1a1a;
+}
+.text-align-center-font .b-font:before {
+  content: "\e64f";
+  color: #1a1a1a;
+}
+.text-align-center-font.native .b-font:before,
+.text-align-center-font.disabled .b-font:before {
+  content: "\e64f";
+  color: #1a1a1a;
+}
+.text-align-right-font .b-font:before {
+  content: "\e651";
+  color: #1a1a1a;
+}
+.text-align-right-font.native .b-font:before,
+.text-align-right-font.disabled .b-font:before {
+  content: "\e651";
+  color: #1a1a1a;
+}
+.img-upload-font .b-font:before {
+  content: "\e6ba";
+  color: #009de3;
+}
+.img-upload-font.native .b-font:before,
+.img-upload-font.disabled .b-font:before {
+  content: "\e6ba";
+  color: #009de3;
+}
+.img-size-font .b-font:before {
+  content: "\e68b";
+  color: #009de3;
+}
+.img-size-font.native .b-font:before,
+.img-size-font.disabled .b-font:before {
+  content: "\e68b";
+  color: #009de3;
+}
+.img-href-font .b-font:before {
+  content: "\e688";
+  color: #009de3;
+}
+.img-href-font.native .b-font:before,
+.img-href-font.disabled .b-font:before {
+  content: "\e688";
+  color: #009de3;
+}
+.img-shutdown-font .b-font:before {
+  content: "\e689";
+  color: #009de3;
+}
+.img-shutdown-font.native .b-font:before,
+.img-shutdown-font.disabled .b-font:before {
+  content: "\e689";
+  color: #009de3;
+}
+.move-font .b-font:before {
+  content: "\e65e";
+  color: #808080;
+}
+.move-font.native .b-font:before,
+.move-font.disabled .b-font:before {
+  content: "\e65e";
+  color: #808080;
+}
+.share-font .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.share-font.native .b-font:before,
+.share-font.disabled .b-font:before {
+  content: "\e65a";
+  color: #808080;
+}
+.new-file-font .b-font:before {
+  content: "\e65d";
+  color: #808080;
+}
+.new-file-font.native .b-font:before,
+.new-file-font.disabled .b-font:before {
+  content: "\e65d";
+  color: #808080;
+}
+.file-font .b-font:before {
+  content: "\e65b";
+  color: #fcc550;
+}
+.file-font.native .b-font:before,
+.file-font.disabled .b-font:before {
+  content: "\e65b";
+  color: #fcc550;
+}
+.folder-font .b-font:before {
+  content: "\e65c";
+  color: #009de3;
+}
+.folder-font.native .b-font:before,
+.folder-font.disabled .b-font:before {
+  content: "\e65c";
+  color: #009de3;
+}
+.letter-font .b-font:before {
+  content: "\e659";
+  color: #808080;
+}
+.letter-font:hover .b-font:before,
+.letter-font:focus .b-font:before,
+.letter-font.hover .b-font:before {
+  content: "\e659";
+  color: #808080;
+}
+.letter-font:active .b-font:before,
+.letter-font.active .b-font:before {
+  content: "\e659";
+  color: #009de3;
+}
+.letter-font.native .b-font:before,
+.letter-font.disabled .b-font:before {
+  content: "\e659";
+  color: #808080;
+}
+.time-font .b-font:before {
+  content: "\e658";
+  color: #808080;
+}
+.time-font:hover .b-font:before,
+.time-font:focus .b-font:before,
+.time-font.hover .b-font:before {
+  content: "\e658";
+  color: #808080;
+}
+.time-font:active .b-font:before,
+.time-font.active .b-font:before {
+  content: "\e658";
+  color: #009de3;
+}
+.time-font.native .b-font:before,
+.time-font.disabled .b-font:before {
+  content: "\e658";
+  color: #808080;
+}
+.rename-font .b-font:before {
+  content: "\e687";
+  color: #808080;
+}
+.rename-font.native .b-font:before,
+.rename-font.disabled .b-font:before {
+  content: "\e687";
+  color: #808080;
+}
+.delete-template-font .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.delete-template-font.native .b-font:before,
+.delete-template-font.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.real-time-font .b-font:before {
+  content: "\e6af";
+  color: #fcc550;
+}
+.real-time-font.native .b-font:before,
+.real-time-font.disabled .b-font:before {
+  content: "\e6af";
+  color: #fcc550;
+}
+.data-source-table-font .b-font:before {
+  content: "\e67b";
+  color: #009de3;
+}
+.data-source-table-font:hover .b-font:before,
+.data-source-table-font:focus .b-font:before,
+.data-source-table-font.hover .b-font:before {
+  content: "\e67b";
+  color: #009de3;
+}
+.data-source-table-font:active .b-font:before,
+.data-source-table-font.active .b-font:before {
+  content: "\e67b";
+  color: #ffffff;
+}
+.data-source-table-font.native .b-font:before,
+.data-source-table-font.disabled .b-font:before {
+  content: "\e67b";
+  color: #009de3;
+}
+.etl-table-font .b-font:before {
+  content: "\e680";
+  color: #009de3;
+}
+.etl-table-font:hover .b-font:before,
+.etl-table-font:focus .b-font:before,
+.etl-table-font.hover .b-font:before {
+  content: "\e680";
+  color: #009de3;
+}
+.etl-table-font:active .b-font:before,
+.etl-table-font.active .b-font:before {
+  content: "\e680";
+  color: #ffffff;
+}
+.etl-table-font.native .b-font:before,
+.etl-table-font.disabled .b-font:before {
+  content: "\e680";
+  color: #009de3;
+}
+.excel-table-font .b-font:before {
+  content: "\e682";
+  color: #009de3;
+}
+.excel-table-font:hover .b-font:before,
+.excel-table-font:focus .b-font:before,
+.excel-table-font.hover .b-font:before {
+  content: "\e682";
+  color: #009de3;
+}
+.excel-table-font:active .b-font:before,
+.excel-table-font.active .b-font:before {
+  content: "\e682";
+  color: #ffffff;
+}
+.excel-table-font.native .b-font:before,
+.excel-table-font.disabled .b-font:before {
+  content: "\e682";
+  color: #009de3;
+}
+.sql-table-font .b-font:before {
+  content: "\e681";
+  color: #009de3;
+}
+.sql-table-font:hover .b-font:before,
+.sql-table-font:focus .b-font:before,
+.sql-table-font.hover .b-font:before {
+  content: "\e681";
+  color: #009de3;
+}
+.sql-table-font:active .b-font:before,
+.sql-table-font.active .b-font:before {
+  content: "\e681";
+  color: #ffffff;
+}
+.sql-table-font.native .b-font:before,
+.sql-table-font.disabled .b-font:before {
+  content: "\e681";
+  color: #009de3;
+}
+.refresh-table-font .b-font:before {
+  content: "\e683";
+  color: #808080;
+}
+.refresh-table-font.native .b-font:before,
+.refresh-table-font.disabled .b-font:before {
+  content: "\e683";
+  color: #808080;
+}
+.recover-chart-font-hightlight .b-font:before {
+  content: "\e6b4";
+  color: #009de3;
+}
+.recover-chart-font-hightlight.native .b-font:before,
+.recover-chart-font-hightlight.disabled .b-font:before {
+  content: "\e6b4";
+  color: #009de3;
+}
+.tables-tile-view-font .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.tables-tile-view-font:hover .b-font:before,
+.tables-tile-view-font:focus .b-font:before,
+.tables-tile-view-font.hover .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.tables-tile-view-font:active .b-font:before,
+.tables-tile-view-font.active .b-font:before {
+  content: "\e685";
+  color: #ffffff;
+}
+.tables-tile-view-font.native .b-font:before,
+.tables-tile-view-font.disabled .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.tables-relation-view-font .b-font:before {
+  content: "\e684";
+  color: #808080;
+}
+.tables-relation-view-font:hover .b-font:before,
+.tables-relation-view-font:focus .b-font:before,
+.tables-relation-view-font.hover .b-font:before {
+  content: "\e684";
+  color: #808080;
+}
+.tables-relation-view-font:active .b-font:before,
+.tables-relation-view-font.active .b-font:before {
+  content: "\e684";
+  color: #ffffff;
+}
+.tables-relation-view-font.native .b-font:before,
+.tables-relation-view-font.disabled .b-font:before {
+  content: "\e684";
+  color: #808080;
+}
+.add-new-table-pull-down-font .b-font:before {
+  content: "\e62d";
+  color: #ffffff;
+}
+.add-new-table-pull-down-font.native .b-font:before,
+.add-new-table-pull-down-font.disabled .b-font:before {
+  content: "\e62d";
+  color: #ffffff;
+}
+.data-link-check-font .b-font:before {
+  content: "\e611";
+  color: #ffffff;
+}
+.data-link-check-font:hover .b-font:before,
+.data-link-check-font:focus .b-font:before,
+.data-link-check-font.hover .b-font:before {
+  content: "\e611";
+  color: #f4f4f4;
+}
+.data-link-check-font:active .b-font:before,
+.data-link-check-font.active .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.data-link-check-font.native .b-font:before,
+.data-link-check-font.disabled .b-font:before {
+  content: "\e611";
+  color: #ffffff;
+}
+.edit-set-font .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.edit-set-font:hover .b-font:before,
+.edit-set-font:focus .b-font:before,
+.edit-set-font.hover .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.edit-set-font.native .b-font:before,
+.edit-set-font.disabled .b-font:before {
+  content: "\e634";
+  color: #808080;
+}
+.new-analysis-font .b-font:before {
+  content: "\e692";
+  color: #ffffff;
+}
+.new-analysis-font:hover .b-font:before,
+.new-analysis-font:focus .b-font:before,
+.new-analysis-font.hover .b-font:before {
+  content: "\e692";
+  color: #ffffff;
+}
+.new-analysis-font.native .b-font:before,
+.new-analysis-font.disabled .b-font:before {
+  content: "\e692";
+  color: #ffffff;
+}
+.data-config-font .b-font:before {
+  content: "\e693";
+  color: #ffffff;
+}
+.data-config-font:hover .b-font:before,
+.data-config-font:focus .b-font:before,
+.data-config-font.hover .b-font:before {
+  content: "\e693";
+  color: #ffffff;
+}
+.data-config-font.native .b-font:before,
+.data-config-font.disabled .b-font:before {
+  content: "\e693";
+  color: #ffffff;
+}
+.folder-list-view .b-font:before {
+  content: "\e694";
+  color: #808080;
+}
+.folder-list-view:hover .b-font:before,
+.folder-list-view:focus .b-font:before,
+.folder-list-view.hover .b-font:before {
+  content: "\e694";
+  color: #808080;
+}
+.folder-list-view:active .b-font:before,
+.folder-list-view.active .b-font:before {
+  content: "\e694";
+  color: #ffffff;
+}
+.folder-list-view.native .b-font:before,
+.folder-list-view.disabled .b-font:before {
+  content: "\e694";
+  color: #808080;
+}
+.folder-card-view .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.folder-card-view:hover .b-font:before,
+.folder-card-view:focus .b-font:before,
+.folder-card-view.hover .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.folder-card-view:active .b-font:before,
+.folder-card-view.active .b-font:before {
+  content: "\e685";
+  color: #ffffff;
+}
+.folder-card-view.native .b-font:before,
+.folder-card-view.disabled .b-font:before {
+  content: "\e685";
+  color: #808080;
+}
+.item-check-font .b-font:before {
+  content: "\e611";
+  color: #ffffff;
+}
+.item-check-font:hover .b-font:before,
+.item-check-font:focus .b-font:before,
+.item-check-font.hover .b-font:before {
+  content: "\e611";
+  color: #f4f4f4;
+}
+.item-check-font:active .b-font:before,
+.item-check-font.active .b-font:before {
+  content: "\e611";
+  color: #009de3;
+}
+.item-check-font.native .b-font:before,
+.item-check-font.disabled .b-font:before {
+  content: "\e611";
+  color: #ffffff;
+}
+.table-no-sort-no-filter-font .b-font:before {
+  content: "\e66a";
+  color: "";
+}
+.table-no-sort-no-filter-font:hover .b-font:before,
+.table-no-sort-no-filter-font:focus .b-font:before,
+.table-no-sort-no-filter-font.hover .b-font:before {
+  content: "\e66a";
+  color: "";
+}
+.table-no-sort-no-filter-font.native .b-font:before,
+.table-no-sort-no-filter-font.disabled .b-font:before {
+  content: "\e66a";
+  color: "";
+}
+.table-no-sort-filter-font .b-font:before {
+  content: "\e66b";
+  color: "";
+}
+.table-no-sort-filter-font:hover .b-font:before,
+.table-no-sort-filter-font:focus .b-font:before,
+.table-no-sort-filter-font.hover .b-font:before {
+  content: "\e66b";
+  color: "";
+}
+.table-no-sort-filter-font.native .b-font:before,
+.table-no-sort-filter-font.disabled .b-font:before {
+  content: "\e66b";
+  color: "";
+}
+.table-descending-filter-font .b-font:before {
+  content: "\e667";
+  color: "";
+}
+.table-descending-filter-font:hover .b-font:before,
+.table-descending-filter-font:focus .b-font:before,
+.table-descending-filter-font.hover .b-font:before {
+  content: "\e667";
+  color: "";
+}
+.table-descending-filter-font.native .b-font:before,
+.table-descending-filter-font.disabled .b-font:before {
+  content: "\e667";
+  color: "";
+}
+.table-ascending-filter-font .b-font:before {
+  content: "\e669";
+  color: "";
+}
+.table-ascending-filter-font:hover .b-font:before,
+.table-ascending-filter-font:focus .b-font:before,
+.table-ascending-filter-font.hover .b-font:before {
+  content: "\e669";
+  color: "";
+}
+.table-ascending-filter-font.native .b-font:before,
+.table-ascending-filter-font.disabled .b-font:before {
+  content: "\e669";
+  color: "";
+}
+.table-descending-no-filter-font .b-font:before {
+  content: "\e666";
+  color: "";
+}
+.table-descending-no-filter-font:hover .b-font:before,
+.table-descending-no-filter-font:focus .b-font:before,
+.table-descending-no-filter-font.hover .b-font:before {
+  content: "\e666";
+  color: "";
+}
+.table-descending-no-filter-font.native .b-font:before,
+.table-descending-no-filter-font.disabled .b-font:before {
+  content: "\e666";
+  color: "";
+}
+.table-ascending-no-filter-font .b-font:before {
+  content: "\e668";
+  color: "";
+}
+.table-ascending-no-filter-font:hover .b-font:before,
+.table-ascending-no-filter-font:focus .b-font:before,
+.table-ascending-no-filter-font.hover .b-font:before {
+  content: "\e668";
+  color: "";
+}
+.table-ascending-no-filter-font.native .b-font:before,
+.table-ascending-no-filter-font.disabled .b-font:before {
+  content: "\e668";
+  color: "";
+}
+.table-no-sort-font .b-font:before {
+  content: "\e66c";
+  color: "";
+}
+.table-no-sort-font:hover .b-font:before,
+.table-no-sort-font:focus .b-font:before,
+.table-no-sort-font.hover .b-font:before {
+  content: "\e66c";
+  color: "";
+}
+.table-no-sort-font.native .b-font:before,
+.table-no-sort-font.disabled .b-font:before {
+  content: "\e66c";
+  color: "";
+}
+.primary-key-font .b-font:before {
+  content: "\e67d;";
+  color: #808080;
+}
+.primary-key-font:hover .b-font:before,
+.primary-key-font:focus .b-font:before,
+.primary-key-font.hover .b-font:before {
+  content: "\e67d;";
+  color: #808080;
+}
+.primary-key-font.native .b-font:before,
+.primary-key-font.disabled .b-font:before {
+  content: "\e67d;";
+  color: #808080;
+}
+.table-open-row-style-font .b-font:before {
+  content: "\e671";
+  color: #808080;
+}
+.table-open-row-style-font:hover .b-font:before,
+.table-open-row-style-font:focus .b-font:before,
+.table-open-row-style-font.hover .b-font:before {
+  content: "\e671";
+  color: #808080;
+}
+.table-open-row-style-font:active .b-font:before,
+.table-open-row-style-font.active .b-font:before {
+  content: "\e671";
+  color: #009de3;
+}
+.table-open-row-style-font.native .b-font:before,
+.table-open-row-style-font.disabled .b-font:before {
+  content: "\e671";
+  color: #808080;
+}
+.table-open-col-style-font .b-font:before {
+  content: "\e672";
+  color: #808080;
+}
+.table-open-col-style-font:hover .b-font:before,
+.table-open-col-style-font:focus .b-font:before,
+.table-open-col-style-font.hover .b-font:before {
+  content: "\e672";
+  color: #808080;
+}
+.table-open-col-style-font:active .b-font:before,
+.table-open-col-style-font.active .b-font:before {
+  content: "\e672";
+  color: #009de3;
+}
+.table-open-col-style-font.native .b-font:before,
+.table-open-col-style-font.disabled .b-font:before {
+  content: "\e672";
+  color: #808080;
+}
+.calculate-function-font .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.calculate-function-font.native .b-font:before,
+.calculate-function-font.disabled .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.path-set-doubt .b-font:before {
+  content: "\e69a";
+  color: #009de3;
+}
+.path-set-doubt.native .b-font:before,
+.path-set-doubt.disabled .b-font:before {
+  content: "\e69a";
+  color: #009de3;
+}
+.rename-report-font .b-font:before {
+  content: "\e687";
+  color: #009de3;
+}
+.rename-report-font.native .b-font:before,
+.rename-report-font.disabled .b-font:before {
+  content: "\e687";
+  color: #009de3;
+}
+.remove-report-font .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.remove-report-font.native .b-font:before,
+.remove-report-font.disabled .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.excel-upload-tip-font .b-font:before {
+  content: "\e69e";
+  color: #009de3;
+}
+.excel-upload-tip-font.native .b-font:before,
+.excel-upload-tip-font.disabled .b-font:before {
+  content: "\e69e";
+  color: #009de3;
+}
+.excel-field-type-string-font .b-font:before {
+  content: "\e622";
+  color: #009de3;
+}
+.excel-field-type-string-font.native .b-font:before,
+.excel-field-type-string-font.disabled .b-font:before {
+  content: "\e622";
+  color: #009de3;
+}
+.excel-field-type-number-font .b-font:before {
+  content: "\e61f";
+  color: #009de3;
+}
+.excel-field-type-number-font.native .b-font:before,
+.excel-field-type-number-font.disabled .b-font:before {
+  content: "\e61f";
+  color: #009de3;
+}
+.excel-field-type-date-font .b-font:before {
+  content: "\e61b";
+  color: #009de3;
+}
+.excel-field-type-date-font.native .b-font:before,
+.excel-field-type-date-font.disabled .b-font:before {
+  content: "\e61b";
+  color: #009de3;
+}
+.excel-field-type-pull-down-font .b-font:before {
+  content: "\e608";
+  color: #009de3;
+}
+.excel-field-type-pull-down-font.native .b-font:before,
+.excel-field-type-pull-down-font.disabled .b-font:before {
+  content: "\e608";
+  color: #009de3;
+}
+.data-link-set-font .b-font:before {
+  content: "\e678";
+  color: #009de3;
+}
+.data-link-set-font.native .b-font:before,
+.data-link-set-font.disabled .b-font:before {
+  content: "\e678";
+  color: #009de3;
+}
+.data-link-test-font .b-font:before {
+  content: "\e686";
+  color: #009de3;
+}
+.data-link-test-font.native .b-font:before,
+.data-link-test-font.disabled .b-font:before {
+  content: "\e686";
+  color: #009de3;
+}
+.data-link-copy-font .b-font:before {
+  content: "\e610";
+  color: #58cc7d;
+}
+.data-link-copy-font.native .b-font:before,
+.data-link-copy-font.disabled .b-font:before {
+  content: "\e610";
+  color: #58cc7d;
+}
+.data-link-remove-font .b-font:before {
+  content: "\e600";
+  color: #e85050;
+}
+.data-link-remove-font.native .b-font:before,
+.data-link-remove-font.disabled .b-font:before {
+  content: "\e600";
+  color: #e85050;
+}
+.cube-path-confirm-font .b-font:before {
+  content: "\e64e";
+  color: #fbb03b;
+}
+.cube-path-confirm-font.native .b-font:before,
+.cube-path-confirm-font.disabled .b-font:before {
+  content: "\e64e";
+  color: #fbb03b;
+}
+.target-style-less-dot-font .b-font:before {
+  content: "\e6a2";
+  color: #e85050;
+}
+.target-style-less-dot-font.native .b-font:before,
+.target-style-less-dot-font.disabled .b-font:before {
+  content: "\e6a2";
+  color: #e85050;
+}
+.target-style-equal-dot-font .b-font:before {
+  content: "\e6a2";
+  color: #f9a744;
+}
+.target-style-equal-dot-font.native .b-font:before,
+.target-style-equal-dot-font.disabled .b-font:before {
+  content: "\e6a2";
+  color: #f9a744;
+}
+.target-style-more-dot-font .b-font:before {
+  content: "\e6a2";
+  color: #58cc7d;
+}
+.target-style-more-dot-font.native .b-font:before,
+.target-style-more-dot-font.disabled .b-font:before {
+  content: "\e6a2";
+  color: #58cc7d;
+}
+.target-style-less-arrow-font .b-font:before {
+  content: "\e6a1";
+  color: #e85050;
+}
+.target-style-less-arrow-font.native .b-font:before,
+.target-style-less-arrow-font.disabled .b-font:before {
+  content: "\e6a1";
+  color: #e85050;
+}
+.target-style-equal-arrow-font .b-font:before {
+  content: "\e69f";
+  color: #f9a744;
+}
+.target-style-equal-arrow-font.native .b-font:before,
+.target-style-equal-arrow-font.disabled .b-font:before {
+  content: "\e69f";
+  color: #f9a744;
+}
+.target-style-more-arrow-font .b-font:before {
+  content: "\e6a0";
+  color: #58cc7d;
+}
+.target-style-more-arrow-font.native .b-font:before,
+.target-style-more-arrow-font.disabled .b-font:before {
+  content: "\e6a0";
+  color: #58cc7d;
+}
+.calculate-target-font .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.calculate-target-font.native .b-font:before,
+.calculate-target-font.disabled .b-font:before {
+  content: "\e6a3";
+  color: #1a1a1a;
+}
+.task-list-font .b-font:before {
+  content: "\e694";
+  color: #009de3;
+}
+.task-list-font.native .b-font:before,
+.task-list-font.disabled .b-font:before {
+  content: "\e694";
+  color: #009de3;
+}
+.widget-combo-detail-font .b-font:before {
+  content: "\e697";
+  color: #009de3;
+}
+.widget-combo-detail-font.native .b-font:before,
+.widget-combo-detail-font.disabled .b-font:before {
+  content: "\e697";
+  color: #009de3;
+}
+.widget-combo-pull-down-font .b-font:before {
+  content: "\e6ab";
+  color: #009de3;
+}
+.widget-combo-pull-down-font.native .b-font:before,
+.widget-combo-pull-down-font.disabled .b-font:before {
+  content: "\e6ab";
+  color: #009de3;
+}
+.widget-tools-filter-font .b-font:before {
+  content: "\e60f";
+  color: #009de3;
+}
+.widget-tools-filter-font.native .b-font:before,
+.widget-tools-filter-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #009de3;
+}
+.widget-tools-clear-font .b-font:before {
+  content: "\e63d";
+  color: #009de3;
+}
+.widget-tools-clear-font.native .b-font:before,
+.widget-tools-clear-font.disabled .b-font:before {
+  content: "\e63d";
+  color: #009de3;
+}
+.widget-tools-export-excel-font .b-font:before {
+  content: "\e635";
+  color: #009de3;
+}
+.widget-tools-export-excel-font.native .b-font:before,
+.widget-tools-export-excel-font.disabled .b-font:before {
+  content: "\e635";
+  color: #009de3;
+}
+.widget-combo-expand-font .b-font:before {
+  content: "\e697";
+  color: #808080;
+}
+.widget-combo-expand-font.native .b-font:before,
+.widget-combo-expand-font.disabled .b-font:before {
+  content: "\e697";
+  color: #808080;
+}
+.widget-combo-linkage-font .b-font:before {
+  content: "\e63c";
+  color: #808080;
+}
+.widget-combo-linkage-font.native .b-font:before,
+.widget-combo-linkage-font.disabled .b-font:before {
+  content: "\e63c";
+  color: #808080;
+}
+.widget-combo-rename-edit-font .b-font:before {
+  content: "\e670";
+  color: #808080;
+}
+.widget-combo-rename-edit-font.native .b-font:before,
+.widget-combo-rename-edit-font.disabled .b-font:before {
+  content: "\e670";
+  color: #808080;
+}
+.widget-combo-show-title-font .b-font:before {
+  content: "\e64c";
+  color: #808080;
+}
+.widget-combo-show-title-font.native .b-font:before,
+.widget-combo-show-title-font.disabled .b-font:before {
+  content: "\e64c";
+  color: #808080;
+}
+.widget-combo-title-left-font .b-font:before {
+  content: "\e654";
+  color: #808080;
+}
+.widget-combo-title-left-font.native .b-font:before,
+.widget-combo-title-left-font.disabled .b-font:before {
+  content: "\e654";
+  color: #808080;
+}
+.widget-combo-title-center-font .b-font:before {
+  content: "\e64f";
+  color: #808080;
+}
+.widget-combo-title-center-font.native .b-font:before,
+.widget-combo-title-center-font.disabled .b-font:before {
+  content: "\e64f";
+  color: #808080;
+}
+.widget-combo-show-filter-font .b-font:before {
+  content: "\e60f";
+  color: #808080;
+}
+.widget-combo-show-filter-font.native .b-font:before,
+.widget-combo-show-filter-font.disabled .b-font:before {
+  content: "\e60f";
+  color: #808080;
+}
+.widget-combo-export-excel-font .b-font:before {
+  content: "\e635";
+  color: #808080;
+}
+.widget-combo-export-excel-font.native .b-font:before,
+.widget-combo-export-excel-font.disabled .b-font:before {
+  content: "\e635";
+  color: #808080;
+}
+.widget-combo-copy .b-font:before {
+  content: "\e610";
+  color: #808080;
+}
+.widget-combo-copy.native .b-font:before,
+.widget-combo-copy.disabled .b-font:before {
+  content: "\e610";
+  color: #808080;
+}
+.widget-combo-delete .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.widget-combo-delete.native .b-font:before,
+.widget-combo-delete.disabled .b-font:before {
+  content: "\e605";
+  color: #808080;
+}
+.widget-combo-asc-font .b-font:before {
+  content: "\e63f";
+  color: #808080;
+}
+.widget-combo-asc-font.native .b-font:before,
+.widget-combo-asc-font.disabled .b-font:before {
+  content: "\e63f";
+  color: #808080;
+}
+.widget-combo-des-font .b-font:before {
+  content: "\e63a";
+  color: #808080;
+}
+.widget-combo-des-font.native .b-font:before,
+.widget-combo-des-font.disabled .b-font:before {
+  content: "\e63a";
+  color: #808080;
+}
+.widget-combo-clear-font .b-font:before {
+  content: "\e63d";
+  color: #808080;
+}
+.widget-combo-clear-font.native .b-font:before,
+.widget-combo-clear-font.disabled .b-font:before {
+  content: "\e63d";
+  color: #808080;
+}
+.detail-table-popup-font .b-font:before {
+  content: "\e6ac";
+  color: #808080;
+}
+.detail-table-popup-font:hover .b-font:before,
+.detail-table-popup-font:focus .b-font:before,
+.detail-table-popup-font.hover .b-font:before {
+  content: "\e6ac";
+  color: #009de3;
+}
+.detail-table-popup-font.native .b-font:before,
+.detail-table-popup-font.disabled .b-font:before {
+  content: "\e6ac";
+  color: #808080;
+}
+.chart-drill-up .b-font:before {
+  content: "\e6ad";
+  color: "";
+}
+.chart-drill-up.native .b-font:before,
+.chart-drill-up.disabled .b-font:before {
+  content: "\e6ad";
+  color: "";
+}
+.chart-drill-down .b-font:before {
+  content: "\e608";
+  color: "";
+}
+.chart-drill-down.native .b-font:before,
+.chart-drill-down.disabled .b-font:before {
+  content: "\e608";
+  color: "";
+}
+.report-filter-open-font .b-font:before {
+  content: "\e648";
+  color: #808080;
+}
+.report-filter-open-font.native .b-font:before,
+.report-filter-open-font.disabled .b-font:before {
+  content: "\e648";
+  color: #808080;
+}
+.report-filter-close-font .b-font:before {
+  content: "\e645";
+  color: #808080;
+}
+.report-filter-close-font.native .b-font:before,
+.report-filter-close-font.disabled .b-font:before {
+  content: "\e645";
+  color: #808080;
+}
+.report-apply-hangout-normal-font .b-font:before {
+  content: "\e66d";
+  color: #808080;
+}
+.report-apply-hangout-normal-font.native .b-font:before,
+.report-apply-hangout-normal-font.disabled .b-font:before {
+  content: "\e66d";
+  color: #808080;
+}
+.report-apply-hangout-ing-font .b-font:before {
+  content: "\e66d";
+  color: #009de3;
+}
+.report-apply-hangout-ing-font.native .b-font:before,
+.report-apply-hangout-ing-font.disabled .b-font:before {
+  content: "\e66d";
+  color: #009de3;
+}
+.report-hangout-font .b-font:before {
+  content: "\e64b";
+  color: #58cc7d;
+}
+.report-hangout-font.native .b-font:before,
+.report-hangout-font.disabled .b-font:before {
+  content: "\e64b";
+  color: #58cc7d;
+}
+.report-cancel-hangout-font .b-font:before {
+  content: "\e64b";
+  color: #808080;
+}
+.report-cancel-hangout-font.native .b-font:before,
+.report-cancel-hangout-font.disabled .b-font:before {
+  content: "\e64b";
+  color: #808080;
+}
+.report-hangout-ing-mark-font .b-font:before {
+  content: "\e64b";
+  color: #009de3;
+}
+.report-hangout-ing-mark-font.native .b-font:before,
+.report-hangout-ing-mark-font.disabled .b-font:before {
+  content: "\e64b";
+  color: #009de3;
+}
+.delete-font-package .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.delete-font-package.native .b-font:before,
+.delete-font-package.disabled .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.delete-h-font-package .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.delete-h-font-package.native .b-font:before,
+.delete-h-font-package.disabled .b-font:before {
+  content: "\e605";
+  color: #e85050;
+}
+.rename-font-package .b-font:before {
+  content: "\e687";
+  color: #009de3;
+}
+.rename-font-package.native .b-font:before,
+.rename-font-package.disabled .b-font:before {
+  content: "\e687";
+  color: #009de3;
+}
+.package-selected-font .b-font:before {
+  content: "\e6b3";
+  color: #178cdf;
+}
+.package-selected-font.native .b-font:before,
+.package-selected-font.disabled .b-font:before {
+  content: "\e6b3";
+  color: #178cdf;
+}
+.package-not-selected-font .b-font:before {
+  content: "\e6b2";
+  color: #178cdf;
+}
+.package-not-selected-font.native .b-font:before,
+.package-not-selected-font.disabled .b-font:before {
+  content: "\e6b2";
+  color: #178cdf;
+}
+.report-detail-info-font .b-font:before {
+  content: "\e66e";
+  color: #f07d0a;
+}
+.report-detail-info-font.native .b-font:before,
+.report-detail-info-font.disabled .b-font:before {
+  content: "\e66e";
+  color: #f07d0a;
+}
+.report-rename-font .b-font:before {
+  content: "\e670";
+  color: #58cc7d;
+}
+.report-rename-font.native .b-font:before,
+.report-rename-font.disabled .b-font:before {
+  content: "\e670";
+  color: #58cc7d;
+}
+.report-cancel-share-font .b-font:before {
+  content: "\e6b5";
+  color: #009de3;
+}
+.report-cancel-share-font.native .b-font:before,
+.report-cancel-share-font.disabled .b-font:before {
+  content: "\e6b5";
+  color: #009de3;
+}
+.drill-push-up-font .b-font:before {
+  content: "\e630";
+  color: #808080;
+}
+.drill-push-up-font.native .b-font:before,
+.drill-push-up-font.disabled .b-font:before {
+  content: "\e630";
+  color: #808080;
+}
+.drill-push-down-font .b-font:before {
+  content: "\e62d";
+  color: #808080;
+}
+.drill-push-down-font.native .b-font:before,
+.drill-push-down-font.disabled .b-font:before {
+  content: "\e62d";
+  color: #808080;
+}
+.drag-tag-font .b-font:before {
+  content: "\e600";
+  color: #f07d0a;
+}
+.drag-tag-font.native .b-font:before,
+.drag-tag-font.disabled .b-font:before {
+  content: "\e600";
+  color: #f07d0a;
+}
+.tree-collapse-icon-type1 .x-icon,
+.tree-collapse-icon-type1:hover .x-icon,
+.tree-collapse-icon-type1:active .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-1.png');
+  _background: none;
+}
+.tree-collapse-icon-type1.native .x-icon,
+.tree-collapse-icon-type1.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-1.png');
+  _background: none;
+}
+.tree-collapse-icon-type2 .x-icon,
+.tree-collapse-icon-type2:hover .x-icon,
+.tree-collapse-icon-type2:active .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-2.png');
+  _background: none;
+}
+.tree-collapse-icon-type2.native .x-icon,
+.tree-collapse-icon-type2.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-2.png');
+  _background: none;
+}
+.tree-collapse-icon-type3 .x-icon,
+.tree-collapse-icon-type3:hover .x-icon,
+.tree-collapse-icon-type3:active .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-3.png');
+  _background: none;
+}
+.tree-collapse-icon-type3.native .x-icon,
+.tree-collapse-icon-type3.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-3.png');
+  _background: none;
+}
+.tree-collapse-icon-type4 .x-icon,
+.tree-collapse-icon-type4:hover .x-icon,
+.tree-collapse-icon-type4:active .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-4.png');
+  _background: none;
+}
+.tree-collapse-icon-type4.native .x-icon,
+.tree-collapse-icon-type4.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-collapse-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-4.png');
+  _background: none;
+}
+.tree-expand-icon-type1 .x-icon,
+.tree-expand-icon-type1:hover .x-icon,
+.tree-expand-icon-type1:active .x-icon {
+  display: block;
+  background: url('icon/tree-expand-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-1.png');
+  _background: none;
+}
+.tree-expand-icon-type1.native .x-icon,
+.tree-expand-icon-type1.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-expand-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-1.png');
+  _background: none;
+}
+.tree-expand-icon-type2 .x-icon,
+.tree-expand-icon-type2:hover .x-icon,
+.tree-expand-icon-type2:active .x-icon {
+  display: block;
+  background: url('icon/tree-expand-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-2.png');
+  _background: none;
+}
+.tree-expand-icon-type2.native .x-icon,
+.tree-expand-icon-type2.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-expand-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-2.png');
+  _background: none;
+}
+.tree-expand-icon-type3 .x-icon,
+.tree-expand-icon-type3:hover .x-icon,
+.tree-expand-icon-type3:active .x-icon {
+  display: block;
+  background: url('icon/tree-expand-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-3.png');
+  _background: none;
+}
+.tree-expand-icon-type3.native .x-icon,
+.tree-expand-icon-type3.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-expand-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-3.png');
+  _background: none;
+}
+.tree-expand-icon-type4 .x-icon,
+.tree-expand-icon-type4:hover .x-icon,
+.tree-expand-icon-type4:active .x-icon {
+  display: block;
+  background: url('icon/tree-expand-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-4.png');
+  _background: none;
+}
+.tree-expand-icon-type4.native .x-icon,
+.tree-expand-icon-type4.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-expand-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-4.png');
+  _background: none;
+}
+.tree-vertical-line-type2 .x-icon,
+.tree-vertical-line-type2:hover .x-icon,
+.tree-vertical-line-type2:active .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
+  _background: none;
+}
+.tree-vertical-line-type2.native .x-icon,
+.tree-vertical-line-type2.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
+  _background: none;
+}
+.tree-vertical-line-type3 .x-icon,
+.tree-vertical-line-type3:hover .x-icon,
+.tree-vertical-line-type3:active .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
+  _background: none;
+}
+.tree-vertical-line-type3.native .x-icon,
+.tree-vertical-line-type3.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
+  _background: none;
+}
+.tree-vertical-line-type4 .x-icon,
+.tree-vertical-line-type4:hover .x-icon,
+.tree-vertical-line-type4:active .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
+  _background: none;
+}
+.tree-vertical-line-type4.native .x-icon,
+.tree-vertical-line-type4.disabled .x-icon {
+  display: block;
+  background: url('icon/tree-vertical-line-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
+  _background: none;
+}
+.check-box-icon .x-icon {
+  display: block;
+  background: url('icon/check-box-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-normal.png');
+  _background: none;
+}
+.check-box-icon:hover .x-icon,
+.check-box-icon:focus .x-icon,
+.check-box-icon.hover .x-icon {
+  display: block;
+  background: url('icon/check-box-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-normal.png');
+  _background: none;
+}
+.check-box-icon:active .x-icon,
+.check-box-icon.active .x-icon {
+  display: block;
+  background: url('icon/check-box-active.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-active.png');
+  _background: none;
+}
+.check-box-icon.native .x-icon,
+.check-box-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/check-box-disable.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-disable.png');
+  _background: none;
+}
+.check-box-icon.native .x-icon,
+.check-box-icon.disabled.active .x-icon {
+  display: block;
+  background: url('icon/check-box-disable2.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-disable2.png');
+  _background: none;
+}
+.radio-icon .x-icon {
+  display: block;
+  background: url('icon/radio-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-normal.png');
+  _background: none;
+}
+.radio-icon:hover .x-icon,
+.radio-icon:focus .x-icon,
+.radio-icon.hover .x-icon {
+  display: block;
+  background: url('icon/radio-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-normal.png');
+  _background: none;
+}
+.radio-icon:active .x-icon,
+.radio-icon.active .x-icon {
+  display: block;
+  background: url('icon/radio-active.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-active.png');
+  _background: none;
+}
+.radio-icon.native .x-icon,
+.radio-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/radio-disable.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-disable.png');
+  _background: none;
+}
+.radio-icon.native .x-icon,
+.radio-icon.disabled.active .x-icon {
+  display: block;
+  background: url('icon/radio-disable2.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-disable2.png');
+  _background: none;
+}
+.check-half-select-icon .x-icon,
+.check-half-select-icon:hover .x-icon,
+.check-half-select-icon:active .x-icon {
+  display: block;
+  background: url('icon/half_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/half_selected.png');
+  _background: none;
+}
+.check-half-select-icon.native .x-icon,
+.check-half-select-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/half_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/half_selected.png');
+  _background: none;
+}
+.loading-bar-icon .x-icon,
+.loading-bar-icon:hover .x-icon,
+.loading-bar-icon:active .x-icon {
+  display: block;
+  background: url('icon/loading_bar.gif') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading_bar.gif');
+  _background: none;
+}
+.loading-bar-icon.native .x-icon,
+.loading-bar-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/loading_bar.gif') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading_bar.gif');
+  _background: none;
+}
+.left-join-icon .x-icon,
+.left-join-icon:hover .x-icon,
+.left-join-icon:active .x-icon {
+  display: block;
+  background: url('icon/left-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/left-join.png');
+  _background: none;
+}
+.left-join-icon.native .x-icon,
+.left-join-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/left-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/left-join.png');
+  _background: none;
+}
+.right-join-icon .x-icon,
+.right-join-icon:hover .x-icon,
+.right-join-icon:active .x-icon {
+  display: block;
+  background: url('icon/right-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/right-join.png');
+  _background: none;
+}
+.right-join-icon.native .x-icon,
+.right-join-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/right-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/right-join.png');
+  _background: none;
+}
+.inner-join-icon .x-icon,
+.inner-join-icon:hover .x-icon,
+.inner-join-icon:active .x-icon {
+  display: block;
+  background: url('icon/inner-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/inner-join.png');
+  _background: none;
+}
+.inner-join-icon.native .x-icon,
+.inner-join-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/inner-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/inner-join.png');
+  _background: none;
+}
+.outer-join-icon .x-icon,
+.outer-join-icon:hover .x-icon,
+.outer-join-icon:active .x-icon {
+  display: block;
+  background: url('icon/outer-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/outer-join.png');
+  _background: none;
+}
+.outer-join-icon.native .x-icon,
+.outer-join-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/outer-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/outer-join.png');
+  _background: none;
+}
+.data-link-test-fail-icon .x-icon,
+.data-link-test-fail-icon:hover .x-icon,
+.data-link-test-fail-icon:active .x-icon {
+  display: block;
+  background: url('icon/test_fail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_fail.png');
+  _background: none;
+}
+.data-link-test-fail-icon.native .x-icon,
+.data-link-test-fail-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/test_fail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_fail.png');
+  _background: none;
+}
+.data-link-test-success-icon .x-icon,
+.data-link-test-success-icon:hover .x-icon,
+.data-link-test-success-icon:active .x-icon {
+  display: block;
+  background: url('icon/test_success.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_success.png');
+  _background: none;
+}
+.data-link-test-success-icon.native .x-icon,
+.data-link-test-success-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/test_success.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_success.png');
+  _background: none;
+}
+.business-package-icon .x-icon,
+.business-package-icon:hover .x-icon,
+.business-package-icon:active .x-icon {
+  display: block;
+  background: url('icon/business_package.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package.png');
+  _background: none;
+}
+.business-package-icon.native .x-icon,
+.business-package-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/business_package.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package.png');
+  _background: none;
+}
+.business-package-add-icon .x-icon,
+.business-package-add-icon:hover .x-icon,
+.business-package-add-icon:active .x-icon {
+  display: block;
+  background: url('icon/business_package_add.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add.png');
+  _background: none;
+}
+.business-package-add-icon.native .x-icon,
+.business-package-add-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/business_package_add.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add.png');
+  _background: none;
+}
+.business-package-add-disable-icon .x-icon,
+.business-package-add-disable-icon:hover .x-icon,
+.business-package-add-disable-icon:active .x-icon {
+  display: block;
+  background: url('icon/business_package_add_disable.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add_disable.png');
+  _background: none;
+}
+.business-package-add-disable-icon.native .x-icon,
+.business-package-add-disable-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/business_package_add_disable.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add_disable.png');
+  _background: none;
+}
+.business-package-selected-icon .x-icon,
+.business-package-selected-icon:hover .x-icon,
+.business-package-selected-icon:active .x-icon {
+  display: block;
+  background: url('icon/package_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/package_selected.png');
+  _background: none;
+}
+.business-package-selected-icon.native .x-icon,
+.business-package-selected-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/package_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/package_selected.png');
+  _background: none;
+}
+.card-view-report-icon .x-icon,
+.card-view-report-icon:hover .x-icon,
+.card-view-report-icon:active .x-icon {
+  display: block;
+  background: url('icon/report.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/report.png');
+  _background: none;
+}
+.card-view-report-icon.native .x-icon,
+.card-view-report-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/report.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/report.png');
+  _background: none;
+}
+.card-view-real-time-icon .x-icon,
+.card-view-real-time-icon:hover .x-icon,
+.card-view-real-time-icon:active .x-icon {
+  display: block;
+  background: url('icon/real_time.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/real_time.png');
+  _background: none;
+}
+.card-view-real-time-icon.native .x-icon,
+.card-view-real-time-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/real_time.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/real_time.png');
+  _background: none;
+}
+.table-style1-icon .x-icon,
+.table-style1-icon:hover .x-icon,
+.table-style1-icon:active .x-icon {
+  display: block;
+  background: url('icon/table_style_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_1.png');
+  _background: none;
+}
+.table-style1-icon.native .x-icon,
+.table-style1-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/table_style_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_1.png');
+  _background: none;
+}
+.table-style2-icon .x-icon,
+.table-style2-icon:hover .x-icon,
+.table-style2-icon:active .x-icon {
+  display: block;
+  background: url('icon/table_style_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_2.png');
+  _background: none;
+}
+.table-style2-icon.native .x-icon,
+.table-style2-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/table_style_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_2.png');
+  _background: none;
+}
+.table-style3-icon .x-icon,
+.table-style3-icon:hover .x-icon,
+.table-style3-icon:active .x-icon {
+  display: block;
+  background: url('icon/table_style_3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_3.png');
+  _background: none;
+}
+.table-style3-icon.native .x-icon,
+.table-style3-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/table_style_3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_3.png');
+  _background: none;
+}
+.axis-chart-style-gradual-icon .x-icon,
+.axis-chart-style-gradual-icon:hover .x-icon,
+.axis-chart-style-gradual-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_gradual.png');
+  _background: none;
+}
+.axis-chart-style-gradual-icon.native .x-icon,
+.axis-chart-style-gradual-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_gradual.png');
+  _background: none;
+}
+.axis-chart-style-gradual-highlight-icon .x-icon,
+.axis-chart-style-gradual-highlight-icon:hover .x-icon,
+.axis-chart-style-gradual-highlight-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_gradual_highlight.png');
+  _background: none;
+}
+.axis-chart-style-gradual-highlight-icon.native .x-icon,
+.axis-chart-style-gradual-highlight-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_gradual_highlight.png');
+  _background: none;
+}
+.axis-chart-style-normal-icon .x-icon,
+.axis-chart-style-normal-icon:hover .x-icon,
+.axis-chart-style-normal-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_normal.png');
+  _background: none;
+}
+.axis-chart-style-normal-icon.native .x-icon,
+.axis-chart-style-normal-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_normal.png');
+  _background: none;
+}
+.axis-chart-style-transparent-icon .x-icon,
+.axis-chart-style-transparent-icon:hover .x-icon,
+.axis-chart-style-transparent-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_transparent.png');
+  _background: none;
+}
+.axis-chart-style-transparent-icon.native .x-icon,
+.axis-chart-style-transparent-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_transparent.png');
+  _background: none;
+}
+.axis-chart-style-3d-icon .x-icon,
+.axis-chart-style-3d-icon:hover .x-icon,
+.axis-chart-style-3d-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_3d.png');
+  _background: none;
+}
+.axis-chart-style-3d-icon.native .x-icon,
+.axis-chart-style-3d-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_3d.png');
+  _background: none;
+}
+.line-chart-style-curve-icon .x-icon,
+.line-chart-style-curve-icon:hover .x-icon,
+.line-chart-style-curve-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_curve.png');
+  _background: none;
+}
+.line-chart-style-curve-icon.native .x-icon,
+.line-chart-style-curve-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_curve.png');
+  _background: none;
+}
+.line-chart-style-broken-icon .x-icon,
+.line-chart-style-broken-icon:hover .x-icon,
+.line-chart-style-broken-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_broken.png');
+  _background: none;
+}
+.line-chart-style-broken-icon.native .x-icon,
+.line-chart-style-broken-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_broken.png');
+  _background: none;
+}
+.line-chart-style-vertical-icon .x-icon,
+.line-chart-style-vertical-icon:hover .x-icon,
+.line-chart-style-vertical-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_vertical.png');
+  _background: none;
+}
+.line-chart-style-vertical-icon.native .x-icon,
+.line-chart-style-vertical-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_vertical.png');
+  _background: none;
+}
+.area-chart-style-curve-icon .x-icon,
+.area-chart-style-curve-icon:hover .x-icon,
+.area-chart-style-curve-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_curve.png');
+  _background: none;
+}
+.area-chart-style-curve-icon.native .x-icon,
+.area-chart-style-curve-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_curve.png');
+  _background: none;
+}
+.area-chart-style-broken-icon .x-icon,
+.area-chart-style-broken-icon:hover .x-icon,
+.area-chart-style-broken-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_broken.png');
+  _background: none;
+}
+.area-chart-style-broken-icon.native .x-icon,
+.area-chart-style-broken-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_broken.png');
+  _background: none;
+}
+.area-chart-style-vertical-icon .x-icon,
+.area-chart-style-vertical-icon:hover .x-icon,
+.area-chart-style-vertical-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_vertical.png');
+  _background: none;
+}
+.area-chart-style-vertical-icon.native .x-icon,
+.area-chart-style-vertical-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_vertical.png');
+  _background: none;
+}
+.pie-chart-style-normal-icon .x-icon,
+.pie-chart-style-normal-icon:hover .x-icon,
+.pie-chart-style-normal-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_normal.png');
+  _background: none;
+}
+.pie-chart-style-normal-icon.native .x-icon,
+.pie-chart-style-normal-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_normal.png');
+  _background: none;
+}
+.pie-chart-style-equal-arc-rose-icon .x-icon,
+.pie-chart-style-equal-arc-rose-icon:hover .x-icon,
+.pie-chart-style-equal-arc-rose-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_equal_arc_rose.png');
+  _background: none;
+}
+.pie-chart-style-equal-arc-rose-icon.native .x-icon,
+.pie-chart-style-equal-arc-rose-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_equal_arc_rose.png');
+  _background: none;
+}
+.pie-chart-style-not-equal-arc-rose-icon .x-icon,
+.pie-chart-style-not-equal-arc-rose-icon:hover .x-icon,
+.pie-chart-style-not-equal-arc-rose-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
+  _background: none;
+}
+.pie-chart-style-not-equal-arc-rose-icon.native .x-icon,
+.pie-chart-style-not-equal-arc-rose-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
+  _background: none;
+}
+.radar-chart-style-polygon-icon .x-icon,
+.radar-chart-style-polygon-icon:hover .x-icon,
+.radar-chart-style-polygon-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_polygon.png');
+  _background: none;
+}
+.radar-chart-style-polygon-icon.native .x-icon,
+.radar-chart-style-polygon-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_polygon.png');
+  _background: none;
+}
+.acc_radar-chart-style-polygon-icon .x-icon,
+.acc_radar-chart-style-polygon-icon:hover .x-icon,
+.acc_radar-chart-style-polygon-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_polygon.png');
+  _background: none;
+}
+.acc_radar-chart-style-polygon-icon.native .x-icon,
+.acc_radar-chart-style-polygon-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_polygon.png');
+  _background: none;
+}
+.acc_radar-chart-style-circle-icon .x-icon,
+.acc_radar-chart-style-circle-icon:hover .x-icon,
+.acc_radar-chart-style-circle-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_circle.png');
+  _background: none;
+}
+.acc_radar-chart-style-circle-icon.native .x-icon,
+.acc_radar-chart-style-circle-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_circle.png');
+  _background: none;
+}
+.radar-chart-style-circle-icon .x-icon,
+.radar-chart-style-circle-icon:hover .x-icon,
+.radar-chart-style-circle-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_circle.png');
+  _background: none;
+}
+.radar-chart-style-circle-icon.native .x-icon,
+.radar-chart-style-circle-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_circle.png');
+  _background: none;
+}
+.dashboard-chart-style-360-icon .x-icon,
+.dashboard-chart-style-360-icon:hover .x-icon,
+.dashboard-chart-style-360-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_1.png');
+  _background: none;
+}
+.dashboard-chart-style-360-icon.native .x-icon,
+.dashboard-chart-style-360-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_1.png');
+  _background: none;
+}
+.dashboard-chart-style-180-icon .x-icon,
+.dashboard-chart-style-180-icon:hover .x-icon,
+.dashboard-chart-style-180-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_2.png');
+  _background: none;
+}
+.dashboard-chart-style-180-icon.native .x-icon,
+.dashboard-chart-style-180-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_2.png');
+  _background: none;
+}
+.dashboard-chart-style-percent-icon .x-icon,
+.dashboard-chart-style-percent-icon:hover .x-icon,
+.dashboard-chart-style-percent-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_4.png');
+  _background: none;
+}
+.dashboard-chart-style-percent-icon.native .x-icon,
+.dashboard-chart-style-percent-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_4.png');
+  _background: none;
+}
+.dashboard-chart-style-percent-scale-slot-icon .x-icon,
+.dashboard-chart-style-percent-scale-slot-icon:hover .x-icon,
+.dashboard-chart-style-percent-scale-slot-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_5.png');
+  _background: none;
+}
+.dashboard-chart-style-percent-scale-slot-icon.native .x-icon,
+.dashboard-chart-style-percent-scale-slot-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_5.png');
+  _background: none;
+}
+.dashboard-chart-style-vertical-tube-icon .x-icon,
+.dashboard-chart-style-vertical-tube-icon:hover .x-icon,
+.dashboard-chart-style-vertical-tube-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_6.png');
+  _background: none;
+}
+.dashboard-chart-style-vertical-tube-icon.native .x-icon,
+.dashboard-chart-style-vertical-tube-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_6.png');
+  _background: none;
+}
+.dashboard-chart-style-horizontal-tube-icon .x-icon,
+.dashboard-chart-style-horizontal-tube-icon:hover .x-icon,
+.dashboard-chart-style-horizontal-tube-icon:active .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_7.png');
+  _background: none;
+}
+.dashboard-chart-style-horizontal-tube-icon.native .x-icon,
+.dashboard-chart-style-horizontal-tube-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_7.png');
+  _background: none;
+}
+.example-excel-icon .x-icon,
+.example-excel-icon:hover .x-icon,
+.example-excel-icon:active .x-icon {
+  display: block;
+  background: url('icon/example.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/example.png');
+  _background: none;
+}
+.example-excel-icon.native .x-icon,
+.example-excel-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/example.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/example.png');
+  _background: none;
+}
+.dimension-no-data-icon .x-icon,
+.dimension-no-data-icon:hover .x-icon,
+.dimension-no-data-icon:active .x-icon {
+  display: block;
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
+  _background: none;
+}
+.dimension-no-data-icon.native .x-icon,
+.dimension-no-data-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
+  _background: none;
+}
+.drag-group-icon .x-icon,
+.drag-group-icon:hover .x-icon,
+.drag-group-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_group.png');
+  _background: none;
+}
+.drag-group-icon.native .x-icon,
+.drag-group-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_group.png');
+  _background: none;
+}
+.drag-cross-icon .x-icon,
+.drag-cross-icon:hover .x-icon,
+.drag-cross-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_cross.png');
+  _background: none;
+}
+.drag-cross-icon.native .x-icon,
+.drag-cross-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_cross.png');
+  _background: none;
+}
+.drag-complex-icon .x-icon,
+.drag-complex-icon:hover .x-icon,
+.drag-complex-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_complex.png');
+  _background: none;
+}
+.drag-complex-icon.native .x-icon,
+.drag-complex-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_complex.png');
+  _background: none;
+}
+.drag-axis-icon .x-icon,
+.drag-axis-icon:hover .x-icon,
+.drag-axis-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis.png');
+  _background: none;
+}
+.drag-axis-icon.native .x-icon,
+.drag-axis-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis.png');
+  _background: none;
+}
+.drag-axis-accu-icon .x-icon,
+.drag-axis-accu-icon:hover .x-icon,
+.drag-axis-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_a.png');
+  _background: none;
+}
+.drag-axis-accu-icon.native .x-icon,
+.drag-axis-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_a.png');
+  _background: none;
+}
+.drag-axis-percent-accu-icon .x-icon,
+.drag-axis-percent-accu-icon:hover .x-icon,
+.drag-axis-percent-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_pa.png');
+  _background: none;
+}
+.drag-axis-percent-accu-icon.native .x-icon,
+.drag-axis-percent-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_pa.png');
+  _background: none;
+}
+.drag-axis-compare-icon .x-icon,
+.drag-axis-compare-icon:hover .x-icon,
+.drag-axis-compare-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_c.png');
+  _background: none;
+}
+.drag-axis-compare-icon.native .x-icon,
+.drag-axis-compare-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_c.png');
+  _background: none;
+}
+.drag-axis-fall-icon .x-icon,
+.drag-axis-fall-icon:hover .x-icon,
+.drag-axis-fall-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_f.png');
+  _background: none;
+}
+.drag-axis-fall-icon.native .x-icon,
+.drag-axis-fall-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_f.png');
+  _background: none;
+}
+.drag-bar-icon .x-icon,
+.drag-bar-icon:hover .x-icon,
+.drag-bar-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar.png');
+  _background: none;
+}
+.drag-bar-icon.native .x-icon,
+.drag-bar-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar.png');
+  _background: none;
+}
+.drag-bar-accu-icon .x-icon,
+.drag-bar-accu-icon:hover .x-icon,
+.drag-bar-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_a.png');
+  _background: none;
+}
+.drag-bar-accu-icon.native .x-icon,
+.drag-bar-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_a.png');
+  _background: none;
+}
+.drag-bar-compare-icon .x-icon,
+.drag-bar-compare-icon:hover .x-icon,
+.drag-bar-compare-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_c.png');
+  _background: none;
+}
+.drag-bar-compare-icon.native .x-icon,
+.drag-bar-compare-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_c.png');
+  _background: none;
+}
+.drag-area-icon .x-icon,
+.drag-area-icon:hover .x-icon,
+.drag-area-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area.png');
+  _background: none;
+}
+.drag-area-icon.native .x-icon,
+.drag-area-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area.png');
+  _background: none;
+}
+.drag-area-accu-icon .x-icon,
+.drag-area-accu-icon:hover .x-icon,
+.drag-area-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_a.png');
+  _background: none;
+}
+.drag-area-accu-icon.native .x-icon,
+.drag-area-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_a.png');
+  _background: none;
+}
+.drag-area-percent-accu-icon .x-icon,
+.drag-area-percent-accu-icon:hover .x-icon,
+.drag-area-percent-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_pa.png');
+  _background: none;
+}
+.drag-area-percent-accu-icon.native .x-icon,
+.drag-area-percent-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_pa.png');
+  _background: none;
+}
+.drag-area-compare-icon .x-icon,
+.drag-area-compare-icon:hover .x-icon,
+.drag-area-compare-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_c.png');
+  _background: none;
+}
+.drag-area-compare-icon.native .x-icon,
+.drag-area-compare-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_c.png');
+  _background: none;
+}
+.drag-area-range-icon .x-icon,
+.drag-area-range-icon:hover .x-icon,
+.drag-area-range-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_r.png');
+  _background: none;
+}
+.drag-area-range-icon.native .x-icon,
+.drag-area-range-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_r.png');
+  _background: none;
+}
+.drag-combine-icon .x-icon,
+.drag-combine-icon:hover .x-icon,
+.drag-combine-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine.png');
+  _background: none;
+}
+.drag-combine-icon.native .x-icon,
+.drag-combine-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine.png');
+  _background: none;
+}
+.drag-combine-mult-icon .x-icon,
+.drag-combine-mult-icon:hover .x-icon,
+.drag-combine-mult-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine_m.png');
+  _background: none;
+}
+.drag-combine-mult-icon.native .x-icon,
+.drag-combine-mult-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine_m.png');
+  _background: none;
+}
+.drag-line-icon .x-icon,
+.drag-line-icon:hover .x-icon,
+.drag-line-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_line.png');
+  _background: none;
+}
+.drag-line-icon.native .x-icon,
+.drag-line-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_line.png');
+  _background: none;
+}
+.drag-pie-icon .x-icon,
+.drag-pie-icon:hover .x-icon,
+.drag-pie-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_pie.png');
+  _background: none;
+}
+.drag-pie-icon.native .x-icon,
+.drag-pie-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_pie.png');
+  _background: none;
+}
+.drag-map-china-icon .x-icon,
+.drag-map-china-icon:hover .x-icon,
+.drag-map-china-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_c.png');
+  _background: none;
+}
+.drag-map-china-icon.native .x-icon,
+.drag-map-china-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_c.png');
+  _background: none;
+}
+.drag-map-global-icon .x-icon,
+.drag-map-global-icon:hover .x-icon,
+.drag-map-global-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_g.png');
+  _background: none;
+}
+.drag-map-global-icon.native .x-icon,
+.drag-map-global-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_g.png');
+  _background: none;
+}
+.drag-map-svg-icon .x-icon,
+.drag-map-svg-icon:hover .x-icon,
+.drag-map-svg-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_s.png');
+  _background: none;
+}
+.drag-map-svg-icon.native .x-icon,
+.drag-map-svg-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_s.png');
+  _background: none;
+}
+.drag-map-gis-icon .x-icon,
+.drag-map-gis-icon:hover .x-icon,
+.drag-map-gis-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_gis.png');
+  _background: none;
+}
+.drag-map-gis-icon.native .x-icon,
+.drag-map-gis-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_gis.png');
+  _background: none;
+}
+.drag-dashboard-icon .x-icon,
+.drag-dashboard-icon:hover .x-icon,
+.drag-dashboard-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_dashboard.png');
+  _background: none;
+}
+.drag-dashboard-icon.native .x-icon,
+.drag-dashboard-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_dashboard.png');
+  _background: none;
+}
+.drag-donut-icon .x-icon,
+.drag-donut-icon:hover .x-icon,
+.drag-donut-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_donut.png');
+  _background: none;
+}
+.drag-donut-icon.native .x-icon,
+.drag-donut-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_donut.png');
+  _background: none;
+}
+.drag-radar-icon .x-icon,
+.drag-radar-icon:hover .x-icon,
+.drag-radar-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar.png');
+  _background: none;
+}
+.drag-radar-icon.native .x-icon,
+.drag-radar-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar.png');
+  _background: none;
+}
+.drag-radar-accu-icon .x-icon,
+.drag-radar-accu-icon:hover .x-icon,
+.drag-radar-accu-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar_a.png');
+  _background: none;
+}
+.drag-radar-accu-icon.native .x-icon,
+.drag-radar-accu-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar_a.png');
+  _background: none;
+}
+.drag-bubble-icon .x-icon,
+.drag-bubble-icon:hover .x-icon,
+.drag-bubble-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble.png');
+  _background: none;
+}
+.drag-bubble-icon.native .x-icon,
+.drag-bubble-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble.png');
+  _background: none;
+}
+.drag-bubble-force-icon .x-icon,
+.drag-bubble-force-icon:hover .x-icon,
+.drag-bubble-force-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble_f.png');
+  _background: none;
+}
+.drag-bubble-force-icon.native .x-icon,
+.drag-bubble-force-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble_f.png');
+  _background: none;
+}
+.drag-scatter-icon .x-icon,
+.drag-scatter-icon:hover .x-icon,
+.drag-scatter-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_scatter.png');
+  _background: none;
+}
+.drag-scatter-icon.native .x-icon,
+.drag-scatter-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_scatter.png');
+  _background: none;
+}
+.drag-funnel-icon .x-icon,
+.drag-funnel-icon:hover .x-icon,
+.drag-funnel-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_funnel.png');
+  _background: none;
+}
+.drag-funnel-icon.native .x-icon,
+.drag-funnel-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_funnel.png');
+  _background: none;
+}
+.drag-detail-icon .x-icon,
+.drag-detail-icon:hover .x-icon,
+.drag-detail-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_detail.png');
+  _background: none;
+}
+.drag-detail-icon.native .x-icon,
+.drag-detail-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_detail.png');
+  _background: none;
+}
+.drag-input-icon .x-icon,
+.drag-input-icon:hover .x-icon,
+.drag-input-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_input.png');
+  _background: none;
+}
+.drag-input-icon.native .x-icon,
+.drag-input-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_input.png');
+  _background: none;
+}
+.drag-web-icon .x-icon,
+.drag-web-icon:hover .x-icon,
+.drag-web-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_web.png');
+  _background: none;
+}
+.drag-web-icon.native .x-icon,
+.drag-web-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_web.png');
+  _background: none;
+}
+.drag-image-icon .x-icon,
+.drag-image-icon:hover .x-icon,
+.drag-image-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_image.png');
+  _background: none;
+}
+.drag-image-icon.native .x-icon,
+.drag-image-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_image.png');
+  _background: none;
+}
+.drag-string-icon .x-icon,
+.drag-string-icon:hover .x-icon,
+.drag-string-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_string.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_string.png');
+  _background: none;
+}
+.drag-string-icon.native .x-icon,
+.drag-string-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_string.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_string.png');
+  _background: none;
+}
+.drag-number-icon .x-icon,
+.drag-number-icon:hover .x-icon,
+.drag-number-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_number.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_number.png');
+  _background: none;
+}
+.drag-number-icon.native .x-icon,
+.drag-number-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_number.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_number.png');
+  _background: none;
+}
+.drag-tree-icon .x-icon,
+.drag-tree-icon:hover .x-icon,
+.drag-tree-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_tree.png');
+  _background: none;
+}
+.drag-tree-icon.native .x-icon,
+.drag-tree-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_tree.png');
+  _background: none;
+}
+.drag-date-icon .x-icon,
+.drag-date-icon:hover .x-icon,
+.drag-date-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_date.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_date.png');
+  _background: none;
+}
+.drag-date-icon.native .x-icon,
+.drag-date-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_date.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_date.png');
+  _background: none;
+}
+.drag-year-icon .x-icon,
+.drag-year-icon:hover .x-icon,
+.drag-year-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year.png');
+  _background: none;
+}
+.drag-year-icon.native .x-icon,
+.drag-year-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year.png');
+  _background: none;
+}
+.drag-year-month-icon .x-icon,
+.drag-year-month-icon:hover .x-icon,
+.drag-year-month-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m.png');
+  _background: none;
+}
+.drag-year-month-icon.native .x-icon,
+.drag-year-month-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m.png');
+  _background: none;
+}
+.drag-year-season-icon .x-icon,
+.drag-year-season-icon:hover .x-icon,
+.drag-year-season-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_s.png');
+  _background: none;
+}
+.drag-year-season-icon.native .x-icon,
+.drag-year-season-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_s.png');
+  _background: none;
+}
+.drag-ymd-icon .x-icon,
+.drag-ymd-icon:hover .x-icon,
+.drag-ymd-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m_d.png');
+  _background: none;
+}
+.drag-ymd-icon.native .x-icon,
+.drag-ymd-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m_d.png');
+  _background: none;
+}
+.drag-general-query-icon .x-icon,
+.drag-general-query-icon:hover .x-icon,
+.drag-general-query-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query_g.png');
+  _background: none;
+}
+.drag-general-query-icon.native .x-icon,
+.drag-general-query-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query_g.png');
+  _background: none;
+}
+.drag-query-icon .x-icon,
+.drag-query-icon:hover .x-icon,
+.drag-query-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_query.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query.png');
+  _background: none;
+}
+.drag-query-icon.native .x-icon,
+.drag-query-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_query.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query.png');
+  _background: none;
+}
+.drag-reset-icon .x-icon,
+.drag-reset-icon:hover .x-icon,
+.drag-reset-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reset.png');
+  _background: none;
+}
+.drag-reset-icon.native .x-icon,
+.drag-reset-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reset.png');
+  _background: none;
+}
+.drag-reuse-icon .x-icon,
+.drag-reuse-icon:hover .x-icon,
+.drag-reuse-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reuse.png');
+  _background: none;
+}
+.drag-reuse-icon.native .x-icon,
+.drag-reuse-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reuse.png');
+  _background: none;
+}
+.drag-group-small-icon .x-icon,
+.drag-group-small-icon:hover .x-icon,
+.drag-group-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_group.png');
+  _background: none;
+}
+.drag-group-small-icon.native .x-icon,
+.drag-group-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_group.png');
+  _background: none;
+}
+.drag-cross-small-icon .x-icon,
+.drag-cross-small-icon:hover .x-icon,
+.drag-cross-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_cross.png');
+  _background: none;
+}
+.drag-cross-small-icon.native .x-icon,
+.drag-cross-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_cross.png');
+  _background: none;
+}
+.drag-complex-small-icon .x-icon,
+.drag-complex-small-icon:hover .x-icon,
+.drag-complex-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_complex.png');
+  _background: none;
+}
+.drag-complex-small-icon.native .x-icon,
+.drag-complex-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_complex.png');
+  _background: none;
+}
+.drag-axis-small-icon .x-icon,
+.drag-axis-small-icon:hover .x-icon,
+.drag-axis-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis.png');
+  _background: none;
+}
+.drag-axis-small-icon.native .x-icon,
+.drag-axis-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis.png');
+  _background: none;
+}
+.drag-axis-accu-small-icon .x-icon,
+.drag-axis-accu-small-icon:hover .x-icon,
+.drag-axis-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_a.png');
+  _background: none;
+}
+.drag-axis-accu-small-icon.native .x-icon,
+.drag-axis-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_a.png');
+  _background: none;
+}
+.drag-axis-percent-accu-small-icon .x-icon,
+.drag-axis-percent-accu-small-icon:hover .x-icon,
+.drag-axis-percent-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_pa.png');
+  _background: none;
+}
+.drag-axis-percent-accu-small-icon.native .x-icon,
+.drag-axis-percent-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_pa.png');
+  _background: none;
+}
+.drag-axis-compare-small-icon .x-icon,
+.drag-axis-compare-small-icon:hover .x-icon,
+.drag-axis-compare-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_c.png');
+  _background: none;
+}
+.drag-axis-compare-small-icon.native .x-icon,
+.drag-axis-compare-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_c.png');
+  _background: none;
+}
+.drag-axis-fall-small-icon .x-icon,
+.drag-axis-fall-small-icon:hover .x-icon,
+.drag-axis-fall-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_f.png');
+  _background: none;
+}
+.drag-axis-fall-small-icon.native .x-icon,
+.drag-axis-fall-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_f.png');
+  _background: none;
+}
+.drag-bar-small-icon .x-icon,
+.drag-bar-small-icon:hover .x-icon,
+.drag-bar-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar.png');
+  _background: none;
+}
+.drag-bar-small-icon.native .x-icon,
+.drag-bar-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar.png');
+  _background: none;
+}
+.drag-bar-accu-small-icon .x-icon,
+.drag-bar-accu-small-icon:hover .x-icon,
+.drag-bar-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_a.png');
+  _background: none;
+}
+.drag-bar-accu-small-icon.native .x-icon,
+.drag-bar-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_a.png');
+  _background: none;
+}
+.drag-bar-compare-small-icon .x-icon,
+.drag-bar-compare-small-icon:hover .x-icon,
+.drag-bar-compare-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_c.png');
+  _background: none;
+}
+.drag-bar-compare-small-icon.native .x-icon,
+.drag-bar-compare-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_c.png');
+  _background: none;
+}
+.drag-area-small-icon .x-icon,
+.drag-area-small-icon:hover .x-icon,
+.drag-area-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area.png');
+  _background: none;
+}
+.drag-area-small-icon.native .x-icon,
+.drag-area-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area.png');
+  _background: none;
+}
+.drag-area-accu-small-icon .x-icon,
+.drag-area-accu-small-icon:hover .x-icon,
+.drag-area-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_a.png');
+  _background: none;
+}
+.drag-area-accu-small-icon.native .x-icon,
+.drag-area-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_a.png');
+  _background: none;
+}
+.drag-area-percent-accu-small-icon .x-icon,
+.drag-area-percent-accu-small-icon:hover .x-icon,
+.drag-area-percent-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_pa.png');
+  _background: none;
+}
+.drag-area-percent-accu-small-icon.native .x-icon,
+.drag-area-percent-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_pa.png');
+  _background: none;
+}
+.drag-area-compare-small-icon .x-icon,
+.drag-area-compare-small-icon:hover .x-icon,
+.drag-area-compare-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_c.png');
+  _background: none;
+}
+.drag-area-compare-small-icon.native .x-icon,
+.drag-area-compare-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_c.png');
+  _background: none;
+}
+.drag-area-range-small-icon .x-icon,
+.drag-area-range-small-icon:hover .x-icon,
+.drag-area-range-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_r.png');
+  _background: none;
+}
+.drag-area-range-small-icon.native .x-icon,
+.drag-area-range-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_r.png');
+  _background: none;
+}
+.drag-combine-small-icon .x-icon,
+.drag-combine-small-icon:hover .x-icon,
+.drag-combine-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine.png');
+  _background: none;
+}
+.drag-combine-small-icon.native .x-icon,
+.drag-combine-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine.png');
+  _background: none;
+}
+.drag-combine-mult-small-icon .x-icon,
+.drag-combine-mult-small-icon:hover .x-icon,
+.drag-combine-mult-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine_m.png');
+  _background: none;
+}
+.drag-combine-mult-small-icon.native .x-icon,
+.drag-combine-mult-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine_m.png');
+  _background: none;
+}
+.drag-line-small-icon .x-icon,
+.drag-line-small-icon:hover .x-icon,
+.drag-line-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_line.png');
+  _background: none;
+}
+.drag-line-small-icon.native .x-icon,
+.drag-line-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_line.png');
+  _background: none;
+}
+.drag-pie-small-icon .x-icon,
+.drag-pie-small-icon:hover .x-icon,
+.drag-pie-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_pie.png');
+  _background: none;
+}
+.drag-pie-small-icon.native .x-icon,
+.drag-pie-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_pie.png');
+  _background: none;
+}
+.drag-map-china-small-icon .x-icon,
+.drag-map-china-small-icon:hover .x-icon,
+.drag-map-china-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_c.png');
+  _background: none;
+}
+.drag-map-china-small-icon.native .x-icon,
+.drag-map-china-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_c.png');
+  _background: none;
+}
+.drag-map-global-small-icon .x-icon,
+.drag-map-global-small-icon:hover .x-icon,
+.drag-map-global-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_g.png');
+  _background: none;
+}
+.drag-map-global-small-icon.native .x-icon,
+.drag-map-global-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_g.png');
+  _background: none;
+}
+.drag-map-svg-small-icon .x-icon,
+.drag-map-svg-small-icon:hover .x-icon,
+.drag-map-svg-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_s.png');
+  _background: none;
+}
+.drag-map-svg-small-icon.native .x-icon,
+.drag-map-svg-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_s.png');
+  _background: none;
+}
+.drag-map-gis-small-icon .x-icon,
+.drag-map-gis-small-icon:hover .x-icon,
+.drag-map-gis-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_gis.png');
+  _background: none;
+}
+.drag-map-gis-small-icon.native .x-icon,
+.drag-map-gis-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_gis.png');
+  _background: none;
+}
+.drag-dashboard-small-icon .x-icon,
+.drag-dashboard-small-icon:hover .x-icon,
+.drag-dashboard-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_dashboard.png');
+  _background: none;
+}
+.drag-dashboard-small-icon.native .x-icon,
+.drag-dashboard-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_dashboard.png');
+  _background: none;
+}
+.drag-donut-small-icon .x-icon,
+.drag-donut-small-icon:hover .x-icon,
+.drag-donut-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_donut.png');
+  _background: none;
+}
+.drag-donut-small-icon.native .x-icon,
+.drag-donut-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_donut.png');
+  _background: none;
+}
+.drag-radar-small-icon .x-icon,
+.drag-radar-small-icon:hover .x-icon,
+.drag-radar-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar.png');
+  _background: none;
+}
+.drag-radar-small-icon.native .x-icon,
+.drag-radar-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar.png');
+  _background: none;
+}
+.drag-radar-accu-small-icon .x-icon,
+.drag-radar-accu-small-icon:hover .x-icon,
+.drag-radar-accu-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar_a.png');
+  _background: none;
+}
+.drag-radar-accu-small-icon.native .x-icon,
+.drag-radar-accu-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar_a.png');
+  _background: none;
+}
+.drag-bubble-small-icon .x-icon,
+.drag-bubble-small-icon:hover .x-icon,
+.drag-bubble-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble.png');
+  _background: none;
+}
+.drag-bubble-small-icon.native .x-icon,
+.drag-bubble-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble.png');
+  _background: none;
+}
+.drag-bubble-force-small-icon .x-icon,
+.drag-bubble-force-small-icon:hover .x-icon,
+.drag-bubble-force-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble_f.png');
+  _background: none;
+}
+.drag-bubble-force-small-icon.native .x-icon,
+.drag-bubble-force-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble_f.png');
+  _background: none;
+}
+.drag-scatter-small-icon .x-icon,
+.drag-scatter-small-icon:hover .x-icon,
+.drag-scatter-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_scatter.png');
+  _background: none;
+}
+.drag-scatter-small-icon.native .x-icon,
+.drag-scatter-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_scatter.png');
+  _background: none;
+}
+.drag-funnel-small-icon .x-icon,
+.drag-funnel-small-icon:hover .x-icon,
+.drag-funnel-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_funnel.png');
+  _background: none;
+}
+.drag-funnel-small-icon.native .x-icon,
+.drag-funnel-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_funnel.png');
+  _background: none;
+}
+.drag-detail-small-icon .x-icon,
+.drag-detail-small-icon:hover .x-icon,
+.drag-detail-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_detail.png');
+  _background: none;
+}
+.drag-detail-small-icon.native .x-icon,
+.drag-detail-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_detail.png');
+  _background: none;
+}
+.drag-input-small-icon .x-icon,
+.drag-input-small-icon:hover .x-icon,
+.drag-input-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_input.png');
+  _background: none;
+}
+.drag-input-small-icon.native .x-icon,
+.drag-input-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_input.png');
+  _background: none;
+}
+.drag-web-small-icon .x-icon,
+.drag-web-small-icon:hover .x-icon,
+.drag-web-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_web.png');
+  _background: none;
+}
+.drag-web-small-icon.native .x-icon,
+.drag-web-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_web.png');
+  _background: none;
+}
+.drag-image-small-icon .x-icon,
+.drag-image-small-icon:hover .x-icon,
+.drag-image-small-icon:active .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_image.png');
+  _background: none;
+}
+.drag-image-small-icon.native .x-icon,
+.drag-image-small-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/drag/small/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_image.png');
+  _background: none;
+}
+.error-face-icon .x-icon,
+.error-face-icon:hover .x-icon,
+.error-face-icon:active .x-icon {
+  display: block;
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
+  _background: none;
+}
+.error-face-icon.native .x-icon,
+.error-face-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
+  _background: none;
+}
+.drag-tip-dots-icon .x-icon,
+.drag-tip-dots-icon:hover .x-icon,
+.drag-tip-dots-icon:active .x-icon {
+  display: block;
+  background: url('icon/dots.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/dots.png');
+  _background: none;
+}
+.drag-tip-dots-icon.native .x-icon,
+.drag-tip-dots-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/dots.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/dots.png');
+  _background: none;
+}
+.bubble-no-projector .x-icon,
+.bubble-no-projector:hover .x-icon,
+.bubble-no-projector:active .x-icon {
+  display: block;
+  background: url('icon/bubble_no_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_no_projector.png');
+  _background: none;
+}
+.bubble-no-projector.native .x-icon,
+.bubble-no-projector.disabled .x-icon {
+  display: block;
+  background: url('icon/bubble_no_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_no_projector.png');
+  _background: none;
+}
+.bubble-with-projector .x-icon,
+.bubble-with-projector:hover .x-icon,
+.bubble-with-projector:active .x-icon {
+  display: block;
+  background: url('icon/bubble_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_projector.png');
+  _background: none;
+}
+.bubble-with-projector.native .x-icon,
+.bubble-with-projector.disabled .x-icon {
+  display: block;
+  background: url('icon/bubble_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_projector.png');
+  _background: none;
+}
+.drill-push-down-icon .x-icon,
+.drill-push-down-icon:hover .x-icon,
+.drill-push-down-icon:active .x-icon {
+  display: block;
+  background: url('icon/push_down.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_down.png');
+  _background: none;
+}
+.drill-push-down-icon.native .x-icon,
+.drill-push-down-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/push_down.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_down.png');
+  _background: none;
+}
+.drill-push-up-icon .x-icon,
+.drill-push-up-icon:hover .x-icon,
+.drill-push-up-icon:active .x-icon {
+  display: block;
+  background: url('icon/push_up.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_up.png');
+  _background: none;
+}
+.drill-push-up-icon.native .x-icon,
+.drill-push-up-icon.disabled .x-icon {
+  display: block;
+  background: url('icon/push_up.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_up.png');
+  _background: none;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.y-overflow-auto {
+  overflow-y: auto;
+  overflow-x: hidden;
+}
+.x-overflow-auto {
+  overflow-y: hidden;
+  overflow-x: auto;
+}
+.y-overflow-scroll {
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+.x-overflow-scroll {
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.overflow-auto {
+  overflow-x: auto;
+  overflow-y: auto;
+}
+.overflow-scroll {
+  overflow-x: scroll;
+  overflow-y: scroll;
+}
+.overflow-hidden {
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+.td-overflow {
+  white-space: normal;
+  word-break: break-all;
+}
+.overflow-dot {
+  text-overflow: ellipsis;
+  overflow-x: hidden;
+  white-space: nowrap;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.display-block {
+  display: block;
+}
+.display-inline {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+}
+/**常用于span元素在与combo并列时**/
+.vertical-super {
+  vertical-align: super;
+}
+.vertical-top {
+  vertical-align: top;
+}
+.horizon-center {
+  text-align: center;
+}
+.horizon-left {
+  text-align: left;
+}
+.div-horizon-center {
+  margin-left: auto;
+  margin-right: auto;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*类似ie6的盒子模型 可以在有百分比的时候加border 支持到ie8*/
+.border-sizing {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+}
+.content-sizing {
+  -webkit-box-sizing: content-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: content-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: content-box;
+  /*IE8*/
+  box-sizing: content-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+@font-face {
+  font-family: 'bi';
+  src: url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.woff') format('woff'), /* chrome、firefox */ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.svg#svgFontName') format('svg');
+  
+  /*  iOS 4.1- */
+}
+.b-font {
+  font-family: "bi";
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: 0.2px;
+  -moz-osx-font-smoothing: grayscale;
+}
+html,
+button,
+input,
+select,
+textarea,
+* {
+  font-family: "Microsoft YaHei", "Hiragino Sans GB W3";
+}
+html,
+body,
+div,
+ul,
+li,
+img,
+a,
+span,
+p,
+* {
+  margin: 0px;
+}
+html {
+  height: 100%;
+  overflow: hidden;
+}
+body {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  top: 0;
+  left: 0;
+  background-repeat: repeat;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+  color: #1a1a1a;
+  font: normal 12px "Microsoft YaHei", "Hiragino Sans GB W3";
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-decoration: none;
+  -kthml-user-focus: normal;
+  -moz-user-focus: normal;
+  -moz-outline: 0 none;
+  outline: 0 none;
+}
+#wrapper {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  overflow: hidden;
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+a {
+  outline: none;
+  text-decoration: none;
+}
+a:focus {
+  outline: 0;
+}
+input,
+textarea {
+  margin: 0;
+  padding: 0;
+  outline: none;
+  border: 1px solid #cccccc;
+}
+ul,
+ol {
+  margin: 0;
+  padding: 0;
+}
+ul {
+  list-style: disc;
+}
+li {
+  list-style-type: none;
+}
+i {
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: 0.2px;
+  -moz-osx-font-smoothing: grayscale;
+}
+div::-webkit-scrollbar,
+textarea::-webkit-scrollbar {
+  -webkit-appearance: none;
+  background-color: #f4f4f4;
+  width: 6px;
+  height: 6px;
+}
+div::-webkit-scrollbar-thumb,
+textarea::-webkit-scrollbar-thumb {
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+  background-color: #e2e2e2;
+}
diff --git a/dist/core.js b/dist/core.js
new file mode 100644
index 000000000..559811fa3
--- /dev/null
+++ b/dist/core.js
@@ -0,0 +1,28321 @@
+/*!
+ * jQuery JavaScript Library v1.8.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
+ */
+(function( window, undefined ) {
+var
+	// A central reference to the root jQuery(document)
+	rootjQuery,
+
+	// The deferred used on DOM ready
+	readyList,
+
+	// Use the correct document accordingly with window argument (sandbox)
+	document = window.document,
+	location = window.location,
+	navigator = window.navigator,
+
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$,
+
+	// Save a reference to some core methods
+	core_push = Array.prototype.push,
+	core_slice = Array.prototype.slice,
+	core_indexOf = Array.prototype.indexOf,
+	core_toString = Object.prototype.toString,
+	core_hasOwn = Object.prototype.hasOwnProperty,
+	core_trim = String.prototype.trim,
+
+	// Define a local copy of jQuery
+	jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		return new jQuery.fn.init( selector, context, rootjQuery );
+	},
+
+	// Used for matching numbers
+	core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
+
+	// Used for detecting and trimming whitespace
+	core_rnotwhite = /\S/,
+	core_rspace = /\s+/,
+
+	// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+	// A simple way to check for HTML strings
+	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+	rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+	// Match a standalone tag
+	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+	// JSON RegExp
+	rvalidchars = /^[\],:{}\s]*$/,
+	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+	rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+	rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
+
+	// Matches dashed string for camelizing
+	rmsPrefix = /^-ms-/,
+	rdashAlpha = /-([\da-z])/gi,
+
+	// Used by jQuery.camelCase as callback to replace()
+	fcamelCase = function( all, letter ) {
+		return ( letter + "" ).toUpperCase();
+	},
+
+	// The ready event handler and self cleanup method
+	DOMContentLoaded = function() {
+		if ( document.addEventListener ) {
+			document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+			jQuery.ready();
+		} else if ( document.readyState === "complete" ) {
+			// we're here because readyState === "complete" in oldIE
+			// which is good enough for us to call the dom ready!
+			document.detachEvent( "onreadystatechange", DOMContentLoaded );
+			jQuery.ready();
+		}
+	},
+
+	// [[Class]] -> type pairs
+	class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+	constructor: jQuery,
+	init: function( selector, context, rootjQuery ) {
+		var match, elem, ret, doc;
+
+		// Handle $(""), $(null), $(undefined), $(false)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle $(DOMElement)
+		if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+				// Assume that strings that start and end with <> are HTML and skip the regex check
+				match = [ null, selector, null ];
+
+			} else {
+				match = rquickExpr.exec( selector );
+			}
+
+			// Match html or make sure no context is specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					context = context instanceof jQuery ? context[0] : context;
+					doc = ( context && context.nodeType ? context.ownerDocument || context : document );
+
+					// scripts is true for back-compat
+					selector = jQuery.parseHTML( match[1], doc, true );
+					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+						this.attr.call( selector, context, true );
+					}
+
+					return jQuery.merge( this, selector );
+
+				// HANDLE: $(#id)
+				} else {
+					elem = document.getElementById( match[2] );
+
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE and Opera return items
+						// by name instead of ID
+						if ( elem.id !== match[2] ) {
+							return rootjQuery.find( selector );
+						}
+
+						// Otherwise, we inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return ( context || rootjQuery ).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return this.constructor( context ).find( selector );
+			}
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return rootjQuery.ready( selector );
+		}
+
+		if ( selector.selector !== undefined ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	},
+
+	// Start with an empty selector
+	selector: "",
+
+	// The current version of jQuery being used
+	jquery: "1.8.3",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	// The number of elements contained in the matched element set
+	size: function() {
+		return this.length;
+	},
+
+	toArray: function() {
+		return core_slice.call( this );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num == null ?
+
+			// Return a 'clean' array
+			this.toArray() :
+
+			// Return just the object
+			( num < 0 ? this[ this.length + num ] : this[ num ] );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems, name, selector ) {
+
+		// Build a new jQuery matched element set
+		var ret = jQuery.merge( this.constructor(), elems );
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+
+		ret.context = this.context;
+
+		if ( name === "find" ) {
+			ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+		} else if ( name ) {
+			ret.selector = this.selector + "." + name + "(" + selector + ")";
+		}
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	ready: function( fn ) {
+		// Add the callback
+		jQuery.ready.promise().done( fn );
+
+		return this;
+	},
+
+	eq: function( i ) {
+		i = +i;
+		return i === -1 ?
+			this.slice( i ) :
+			this.slice( i, i + 1 );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	slice: function() {
+		return this.pushStack( core_slice.apply( this, arguments ),
+			"slice", core_slice.call(arguments).join(",") );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	end: function() {
+		return this.prevObject || this.constructor(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: core_push,
+	sort: [].sort,
+	splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+	var options, name, src, copy, copyIsArray, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// extend jQuery itself if only one argument is passed
+	if ( length === i ) {
+		target = this;
+		--i;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && jQuery.isArray(src) ? src : [];
+
+					} else {
+						clone = src && jQuery.isPlainObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	noConflict: function( deep ) {
+		if ( window.$ === jQuery ) {
+			window.$ = _$;
+		}
+
+		if ( deep && window.jQuery === jQuery ) {
+			window.jQuery = _jQuery;
+		}
+
+		return jQuery;
+	},
+
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+
+	// A counter to track how many items to wait for before
+	// the ready event fires. See #6781
+	readyWait: 1,
+
+	// Hold (or release) the ready event
+	holdReady: function( hold ) {
+		if ( hold ) {
+			jQuery.readyWait++;
+		} else {
+			jQuery.ready( true );
+		}
+	},
+
+	// Handle when the DOM is ready
+	ready: function( wait ) {
+
+		// Abort if there are pending holds or we're already ready
+		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+			return;
+		}
+
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( !document.body ) {
+			return setTimeout( jQuery.ready, 1 );
+		}
+
+		// Remember that the DOM is ready
+		jQuery.isReady = true;
+
+		// If a normal DOM Ready event fired, decrement, and wait if need be
+		if ( wait !== true && --jQuery.readyWait > 0 ) {
+			return;
+		}
+
+		// If there are functions bound, to execute
+		readyList.resolveWith( document, [ jQuery ] );
+
+		// Trigger any bound ready events
+		if ( jQuery.fn.trigger ) {
+			jQuery( document ).trigger("ready").off("ready");
+		}
+	},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return jQuery.type(obj) === "function";
+	},
+
+	isArray: Array.isArray || function( obj ) {
+		return jQuery.type(obj) === "array";
+	},
+
+	isWindow: function( obj ) {
+		return obj != null && obj == obj.window;
+	},
+
+	isNumeric: function( obj ) {
+		return !isNaN( parseFloat(obj) ) && isFinite( obj );
+	},
+
+	type: function( obj ) {
+		return obj == null ?
+			String( obj ) :
+			class2type[ core_toString.call(obj) ] || "object";
+	},
+
+	isPlainObject: function( obj ) {
+		// Must be an Object.
+		// Because of IE, we also have to check the presence of the constructor property.
+		// Make sure that DOM nodes and window objects don't pass through, as well
+		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+			return false;
+		}
+
+		try {
+			// Not own constructor property must be Object
+			if ( obj.constructor &&
+				!core_hasOwn.call(obj, "constructor") &&
+				!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+				return false;
+			}
+		} catch ( e ) {
+			// IE8,9 Will throw exceptions on certain host objects #9897
+			return false;
+		}
+
+		// Own properties are enumerated firstly, so to speed up,
+		// if last one is own, then all properties are own.
+
+		var key;
+		for ( key in obj ) {}
+
+		return key === undefined || core_hasOwn.call( obj, key );
+	},
+
+	isEmptyObject: function( obj ) {
+		var name;
+		for ( name in obj ) {
+			return false;
+		}
+		return true;
+	},
+
+	error: function( msg ) {
+		throw new Error( msg );
+	},
+
+	// data: string of html
+	// context (optional): If specified, the fragment will be created in this context, defaults to document
+	// scripts (optional): If true, will include scripts passed in the html string
+	parseHTML: function( data, context, scripts ) {
+		var parsed;
+		if ( !data || typeof data !== "string" ) {
+			return null;
+		}
+		if ( typeof context === "boolean" ) {
+			scripts = context;
+			context = 0;
+		}
+		context = context || document;
+
+		// Single tag
+		if ( (parsed = rsingleTag.exec( data )) ) {
+			return [ context.createElement( parsed[1] ) ];
+		}
+
+		parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
+		return jQuery.merge( [],
+			(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
+	},
+
+	parseJSON: function( data ) {
+		if ( !data || typeof data !== "string") {
+			return null;
+		}
+
+		// Make sure leading/trailing whitespace is removed (IE can't handle it)
+		data = jQuery.trim( data );
+
+		// Attempt to parse using the native JSON parser first
+		if ( window.JSON && window.JSON.parse ) {
+			return window.JSON.parse( data );
+		}
+
+		// Make sure the incoming data is actual JSON
+		// Logic borrowed from http://json.org/json2.js
+		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+			.replace( rvalidtokens, "]" )
+			.replace( rvalidbraces, "")) ) {
+
+			return ( new Function( "return " + data ) )();
+
+		}
+		jQuery.error( "Invalid JSON: " + data );
+	},
+
+	// Cross-browser xml parsing
+	parseXML: function( data ) {
+		var xml, tmp;
+		if ( !data || typeof data !== "string" ) {
+			return null;
+		}
+		try {
+			if ( window.DOMParser ) { // Standard
+				tmp = new DOMParser();
+				xml = tmp.parseFromString( data , "text/xml" );
+			} else { // IE
+				xml = new ActiveXObject( "Microsoft.XMLDOM" );
+				xml.async = "false";
+				xml.loadXML( data );
+			}
+		} catch( e ) {
+			xml = undefined;
+		}
+		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+			jQuery.error( "Invalid XML: " + data );
+		}
+		return xml;
+	},
+
+	noop: function() {},
+
+	// Evaluates a script in a global context
+	// Workarounds based on findings by Jim Driscoll
+	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+	globalEval: function( data ) {
+		if ( data && core_rnotwhite.test( data ) ) {
+			// We use execScript on Internet Explorer
+			// We use an anonymous function so that context is window
+			// rather than jQuery in Firefox
+			( window.execScript || function( data ) {
+				window[ "eval" ].call( window, data );
+			} )( data );
+		}
+	},
+
+	// Convert dashed to camelCase; used by the css and data modules
+	// Microsoft forgot to hump their vendor prefix (#9572)
+	camelCase: function( string ) {
+		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+	},
+
+	// args is for internal usage only
+	each: function( obj, callback, args ) {
+		var name,
+			i = 0,
+			length = obj.length,
+			isObj = length === undefined || jQuery.isFunction( obj );
+
+		if ( args ) {
+			if ( isObj ) {
+				for ( name in obj ) {
+					if ( callback.apply( obj[ name ], args ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( ; i < length; ) {
+					if ( callback.apply( obj[ i++ ], args ) === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isObj ) {
+				for ( name in obj ) {
+					if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( ; i < length; ) {
+					if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return obj;
+	},
+
+	// Use native String.trim function wherever possible
+	trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+		function( text ) {
+			return text == null ?
+				"" :
+				core_trim.call( text );
+		} :
+
+		// Otherwise use our own trimming functionality
+		function( text ) {
+			return text == null ?
+				"" :
+				( text + "" ).replace( rtrim, "" );
+		},
+
+	// results is for internal usage only
+	makeArray: function( arr, results ) {
+		var type,
+			ret = results || [];
+
+		if ( arr != null ) {
+			// The window, strings (and functions) also have 'length'
+			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+			type = jQuery.type( arr );
+
+			if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
+				core_push.call( ret, arr );
+			} else {
+				jQuery.merge( ret, arr );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, arr, i ) {
+		var len;
+
+		if ( arr ) {
+			if ( core_indexOf ) {
+				return core_indexOf.call( arr, elem, i );
+			}
+
+			len = arr.length;
+			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+			for ( ; i < len; i++ ) {
+				// Skip accessing in sparse arrays
+				if ( i in arr && arr[ i ] === elem ) {
+					return i;
+				}
+			}
+		}
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		var l = second.length,
+			i = first.length,
+			j = 0;
+
+		if ( typeof l === "number" ) {
+			for ( ; j < l; j++ ) {
+				first[ i++ ] = second[ j ];
+			}
+
+		} else {
+			while ( second[j] !== undefined ) {
+				first[ i++ ] = second[ j++ ];
+			}
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, inv ) {
+		var retVal,
+			ret = [],
+			i = 0,
+			length = elems.length;
+		inv = !!inv;
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( ; i < length; i++ ) {
+			retVal = !!callback( elems[ i ], i );
+			if ( inv !== retVal ) {
+				ret.push( elems[ i ] );
+			}
+		}
+
+		return ret;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var value, key,
+			ret = [],
+			i = 0,
+			length = elems.length,
+			// jquery objects are treated as arrays
+			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+		// Go through the array, translating each of the items to their
+		if ( isArray ) {
+			for ( ; i < length; i++ ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+
+		// Go through every key on the object,
+		} else {
+			for ( key in elems ) {
+				value = callback( elems[ key ], key, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+		}
+
+		// Flatten any nested arrays
+		return ret.concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	// Bind a function to a context, optionally partially applying any
+	// arguments.
+	proxy: function( fn, context ) {
+		var tmp, args, proxy;
+
+		if ( typeof context === "string" ) {
+			tmp = fn[ context ];
+			context = fn;
+			fn = tmp;
+		}
+
+		// Quick check to determine if target is callable, in the spec
+		// this throws a TypeError, but we will just return undefined.
+		if ( !jQuery.isFunction( fn ) ) {
+			return undefined;
+		}
+
+		// Simulated bind
+		args = core_slice.call( arguments, 2 );
+		proxy = function() {
+			return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
+		};
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+		return proxy;
+	},
+
+	// Multifunctional method to get and set values of a collection
+	// The value/s can optionally be executed if it's a function
+	access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+		var exec,
+			bulk = key == null,
+			i = 0,
+			length = elems.length;
+
+		// Sets many values
+		if ( key && typeof key === "object" ) {
+			for ( i in key ) {
+				jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+			}
+			chainable = 1;
+
+		// Sets one value
+		} else if ( value !== undefined ) {
+			// Optionally, function values get executed if exec is true
+			exec = pass === undefined && jQuery.isFunction( value );
+
+			if ( bulk ) {
+				// Bulk operations only iterate when executing function values
+				if ( exec ) {
+					exec = fn;
+					fn = function( elem, key, value ) {
+						return exec.call( jQuery( elem ), value );
+					};
+
+				// Otherwise they run against the entire set
+				} else {
+					fn.call( elems, value );
+					fn = null;
+				}
+			}
+
+			if ( fn ) {
+				for (; i < length; i++ ) {
+					fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+				}
+			}
+
+			chainable = 1;
+		}
+
+		return chainable ?
+			elems :
+
+			// Gets
+			bulk ?
+				fn.call( elems ) :
+				length ? fn( elems[0], key ) : emptyGet;
+	},
+
+	now: function() {
+		return ( new Date() ).getTime();
+	}
+});
+
+jQuery.ready.promise = function( obj ) {
+	if ( !readyList ) {
+
+		readyList = jQuery.Deferred();
+
+		// Catch cases where $(document).ready() is called after the browser event has already occurred.
+		// we once tried to use readyState "interactive" here, but it caused issues like the one
+		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+		if ( document.readyState === "complete" ) {
+			// Handle it asynchronously to allow scripts the opportunity to delay ready
+			setTimeout( jQuery.ready, 1 );
+
+		// Standards-based browsers support DOMContentLoaded
+		} else if ( document.addEventListener ) {
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", jQuery.ready, false );
+
+		// If IE event model is used
+		} else {
+			// Ensure firing before onload, maybe late but safe also for iframes
+			document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+			// A fallback to window.onload, that will always work
+			window.attachEvent( "onload", jQuery.ready );
+
+			// If IE and not a frame
+			// continually check to see if the document is ready
+			var top = false;
+
+			try {
+				top = window.frameElement == null && document.documentElement;
+			} catch(e) {}
+
+			if ( top && top.doScroll ) {
+				(function doScrollCheck() {
+					if ( !jQuery.isReady ) {
+
+						try {
+							// Use the trick by Diego Perini
+							// http://javascript.nwbox.com/IEContentLoaded/
+							top.doScroll("left");
+						} catch(e) {
+							return setTimeout( doScrollCheck, 50 );
+						}
+
+						// and execute any waiting functions
+						jQuery.ready();
+					}
+				})();
+			}
+		}
+	}
+	return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+	var object = optionsCache[ options ] = {};
+	jQuery.each( options.split( core_rspace ), function( _, flag ) {
+		object[ flag ] = true;
+	});
+	return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *	options: an optional list of space-separated options that will change how
+ *			the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *	once:			will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *	memory:			will keep track of previous values and will call any callback added
+ *					after the list has been fired right away with the latest "memorized"
+ *					values (like a Deferred)
+ *
+ *	unique:			will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *	stopOnFalse:	interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+	// Convert options from String-formatted to Object-formatted if needed
+	// (we check in cache first)
+	options = typeof options === "string" ?
+		( optionsCache[ options ] || createOptions( options ) ) :
+		jQuery.extend( {}, options );
+
+	var // Last fire value (for non-forgettable lists)
+		memory,
+		// Flag to know if list was already fired
+		fired,
+		// Flag to know if list is currently firing
+		firing,
+		// First callback to fire (used internally by add and fireWith)
+		firingStart,
+		// End of the loop when firing
+		firingLength,
+		// Index of currently firing callback (modified by remove if needed)
+		firingIndex,
+		// Actual callback list
+		list = [],
+		// Stack of fire calls for repeatable lists
+		stack = !options.once && [],
+		// Fire callbacks
+		fire = function( data ) {
+			memory = options.memory && data;
+			fired = true;
+			firingIndex = firingStart || 0;
+			firingStart = 0;
+			firingLength = list.length;
+			firing = true;
+			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+					memory = false; // To prevent further calls using add
+					break;
+				}
+			}
+			firing = false;
+			if ( list ) {
+				if ( stack ) {
+					if ( stack.length ) {
+						fire( stack.shift() );
+					}
+				} else if ( memory ) {
+					list = [];
+				} else {
+					self.disable();
+				}
+			}
+		},
+		// Actual Callbacks object
+		self = {
+			// Add a callback or a collection of callbacks to the list
+			add: function() {
+				if ( list ) {
+					// First, we save the current length
+					var start = list.length;
+					(function add( args ) {
+						jQuery.each( args, function( _, arg ) {
+							var type = jQuery.type( arg );
+							if ( type === "function" ) {
+								if ( !options.unique || !self.has( arg ) ) {
+									list.push( arg );
+								}
+							} else if ( arg && arg.length && type !== "string" ) {
+								// Inspect recursively
+								add( arg );
+							}
+						});
+					})( arguments );
+					// Do we need to add the callbacks to the
+					// current firing batch?
+					if ( firing ) {
+						firingLength = list.length;
+					// With memory, if we're not firing then
+					// we should call right away
+					} else if ( memory ) {
+						firingStart = start;
+						fire( memory );
+					}
+				}
+				return this;
+			},
+			// Remove a callback from the list
+			remove: function() {
+				if ( list ) {
+					jQuery.each( arguments, function( _, arg ) {
+						var index;
+						while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+							list.splice( index, 1 );
+							// Handle firing indexes
+							if ( firing ) {
+								if ( index <= firingLength ) {
+									firingLength--;
+								}
+								if ( index <= firingIndex ) {
+									firingIndex--;
+								}
+							}
+						}
+					});
+				}
+				return this;
+			},
+			// Control if a given callback is in the list
+			has: function( fn ) {
+				return jQuery.inArray( fn, list ) > -1;
+			},
+			// Remove all callbacks from the list
+			empty: function() {
+				list = [];
+				return this;
+			},
+			// Have the list do nothing anymore
+			disable: function() {
+				list = stack = memory = undefined;
+				return this;
+			},
+			// Is it disabled?
+			disabled: function() {
+				return !list;
+			},
+			// Lock the list in its current state
+			lock: function() {
+				stack = undefined;
+				if ( !memory ) {
+					self.disable();
+				}
+				return this;
+			},
+			// Is it locked?
+			locked: function() {
+				return !stack;
+			},
+			// Call all callbacks with the given context and arguments
+			fireWith: function( context, args ) {
+				args = args || [];
+				args = [ context, args.slice ? args.slice() : args ];
+				if ( list && ( !fired || stack ) ) {
+					if ( firing ) {
+						stack.push( args );
+					} else {
+						fire( args );
+					}
+				}
+				return this;
+			},
+			// Call all the callbacks with the given arguments
+			fire: function() {
+				self.fireWith( this, arguments );
+				return this;
+			},
+			// To know if the callbacks have already been called at least once
+			fired: function() {
+				return !!fired;
+			}
+		};
+
+	return self;
+};
+jQuery.extend({
+
+	Deferred: function( func ) {
+		var tuples = [
+				// action, add listener, listener list, final state
+				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+				[ "notify", "progress", jQuery.Callbacks("memory") ]
+			],
+			state = "pending",
+			promise = {
+				state: function() {
+					return state;
+				},
+				always: function() {
+					deferred.done( arguments ).fail( arguments );
+					return this;
+				},
+				then: function( /* fnDone, fnFail, fnProgress */ ) {
+					var fns = arguments;
+					return jQuery.Deferred(function( newDefer ) {
+						jQuery.each( tuples, function( i, tuple ) {
+							var action = tuple[ 0 ],
+								fn = fns[ i ];
+							// deferred[ done | fail | progress ] for forwarding actions to newDefer
+							deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
+								function() {
+									var returned = fn.apply( this, arguments );
+									if ( returned && jQuery.isFunction( returned.promise ) ) {
+										returned.promise()
+											.done( newDefer.resolve )
+											.fail( newDefer.reject )
+											.progress( newDefer.notify );
+									} else {
+										newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+									}
+								} :
+								newDefer[ action ]
+							);
+						});
+						fns = null;
+					}).promise();
+				},
+				// Get a promise for this deferred
+				// If obj is provided, the promise aspect is added to the object
+				promise: function( obj ) {
+					return obj != null ? jQuery.extend( obj, promise ) : promise;
+				}
+			},
+			deferred = {};
+
+		// Keep pipe for back-compat
+		promise.pipe = promise.then;
+
+		// Add list-specific methods
+		jQuery.each( tuples, function( i, tuple ) {
+			var list = tuple[ 2 ],
+				stateString = tuple[ 3 ];
+
+			// promise[ done | fail | progress ] = list.add
+			promise[ tuple[1] ] = list.add;
+
+			// Handle state
+			if ( stateString ) {
+				list.add(function() {
+					// state = [ resolved | rejected ]
+					state = stateString;
+
+				// [ reject_list | resolve_list ].disable; progress_list.lock
+				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+			}
+
+			// deferred[ resolve | reject | notify ] = list.fire
+			deferred[ tuple[0] ] = list.fire;
+			deferred[ tuple[0] + "With" ] = list.fireWith;
+		});
+
+		// Make the deferred a promise
+		promise.promise( deferred );
+
+		// Call given func if any
+		if ( func ) {
+			func.call( deferred, deferred );
+		}
+
+		// All done!
+		return deferred;
+	},
+
+	// Deferred helper
+	when: function( subordinate /* , ..., subordinateN */ ) {
+		var i = 0,
+			resolveValues = core_slice.call( arguments ),
+			length = resolveValues.length,
+
+			// the count of uncompleted subordinates
+			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+			// Update function for both resolve and progress values
+			updateFunc = function( i, contexts, values ) {
+				return function( value ) {
+					contexts[ i ] = this;
+					values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+					if( values === progressValues ) {
+						deferred.notifyWith( contexts, values );
+					} else if ( !( --remaining ) ) {
+						deferred.resolveWith( contexts, values );
+					}
+				};
+			},
+
+			progressValues, progressContexts, resolveContexts;
+
+		// add listeners to Deferred subordinates; treat others as resolved
+		if ( length > 1 ) {
+			progressValues = new Array( length );
+			progressContexts = new Array( length );
+			resolveContexts = new Array( length );
+			for ( ; i < length; i++ ) {
+				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+					resolveValues[ i ].promise()
+						.done( updateFunc( i, resolveContexts, resolveValues ) )
+						.fail( deferred.reject )
+						.progress( updateFunc( i, progressContexts, progressValues ) );
+				} else {
+					--remaining;
+				}
+			}
+		}
+
+		// if we're not waiting on anything, resolve the master
+		if ( !remaining ) {
+			deferred.resolveWith( resolveContexts, resolveValues );
+		}
+
+		return deferred.promise();
+	}
+});
+jQuery.support = (function() {
+
+	var support,
+		all,
+		a,
+		select,
+		opt,
+		input,
+		fragment,
+		eventName,
+		i,
+		isSupported,
+		clickFn,
+		div = document.createElement("div");
+
+	// Setup
+	div.setAttribute( "className", "t" );
+	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+	// Support tests won't run in some limited or non-browser environments
+	all = div.getElementsByTagName("*");
+	a = div.getElementsByTagName("a")[ 0 ];
+	if ( !all || !a || !all.length ) {
+		return {};
+	}
+
+	// First batch of tests
+	select = document.createElement("select");
+	opt = select.appendChild( document.createElement("option") );
+	input = div.getElementsByTagName("input")[ 0 ];
+
+	a.style.cssText = "top:1px;float:left;opacity:.5";
+	support = {
+		// IE strips leading whitespace when .innerHTML is used
+		leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+		// Make sure that tbody elements aren't automatically inserted
+		// IE will insert them into empty tables
+		tbody: !div.getElementsByTagName("tbody").length,
+
+		// Make sure that link elements get serialized correctly by innerHTML
+		// This requires a wrapper element in IE
+		htmlSerialize: !!div.getElementsByTagName("link").length,
+
+		// Get the style information from getAttribute
+		// (IE uses .cssText instead)
+		style: /top/.test( a.getAttribute("style") ),
+
+		// Make sure that URLs aren't manipulated
+		// (IE normalizes it by default)
+		hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+		// Make sure that element opacity exists
+		// (IE uses filter instead)
+		// Use a regex to work around a WebKit issue. See #5145
+		opacity: /^0.5/.test( a.style.opacity ),
+
+		// Verify style float existence
+		// (IE uses styleFloat instead of cssFloat)
+		cssFloat: !!a.style.cssFloat,
+
+		// Make sure that if no value is specified for a checkbox
+		// that it defaults to "on".
+		// (WebKit defaults to "" instead)
+		checkOn: ( input.value === "on" ),
+
+		// Make sure that a selected-by-default option has a working selected property.
+		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+		optSelected: opt.selected,
+
+		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+		getSetAttribute: div.className !== "t",
+
+		// Tests for enctype support on a form (#6743)
+		enctype: !!document.createElement("form").enctype,
+
+		// Makes sure cloning an html5 element does not cause problems
+		// Where outerHTML is undefined, this still works
+		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+		// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+		boxModel: ( document.compatMode === "CSS1Compat" ),
+
+		// Will be defined later
+		submitBubbles: true,
+		changeBubbles: true,
+		focusinBubbles: false,
+		deleteExpando: true,
+		noCloneEvent: true,
+		inlineBlockNeedsLayout: false,
+		shrinkWrapBlocks: false,
+		reliableMarginRight: true,
+		boxSizingReliable: true,
+		pixelPosition: false
+	};
+
+	// Make sure checked status is properly cloned
+	input.checked = true;
+	support.noCloneChecked = input.cloneNode( true ).checked;
+
+	// Make sure that the options inside disabled selects aren't marked as disabled
+	// (WebKit marks them as disabled)
+	select.disabled = true;
+	support.optDisabled = !opt.disabled;
+
+	// Test to see if it's possible to delete an expando from an element
+	// Fails in Internet Explorer
+	try {
+		delete div.test;
+	} catch( e ) {
+		support.deleteExpando = false;
+	}
+
+	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+		div.attachEvent( "onclick", clickFn = function() {
+			// Cloning a node shouldn't copy over any
+			// bound event handlers (IE does this)
+			support.noCloneEvent = false;
+		});
+		div.cloneNode( true ).fireEvent("onclick");
+		div.detachEvent( "onclick", clickFn );
+	}
+
+	// Check if a radio maintains its value
+	// after being appended to the DOM
+	input = document.createElement("input");
+	input.value = "t";
+	input.setAttribute( "type", "radio" );
+	support.radioValue = input.value === "t";
+
+	input.setAttribute( "checked", "checked" );
+
+	// #11217 - WebKit loses check when the name is after the checked attribute
+	input.setAttribute( "name", "t" );
+
+	div.appendChild( input );
+	fragment = document.createDocumentFragment();
+	fragment.appendChild( div.lastChild );
+
+	// WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Check if a disconnected checkbox will retain its checked
+	// value of true after appended to the DOM (IE6/7)
+	support.appendChecked = input.checked;
+
+	fragment.removeChild( input );
+	fragment.appendChild( div );
+
+	// Technique from Juriy Zaytsev
+	// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+	// We only care about the case where non-standard event systems
+	// are used, namely in IE. Short-circuiting here helps us to
+	// avoid an eval call (in setAttribute) which can cause CSP
+	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+	if ( div.attachEvent ) {
+		for ( i in {
+			submit: true,
+			change: true,
+			focusin: true
+		}) {
+			eventName = "on" + i;
+			isSupported = ( eventName in div );
+			if ( !isSupported ) {
+				div.setAttribute( eventName, "return;" );
+				isSupported = ( typeof div[ eventName ] === "function" );
+			}
+			support[ i + "Bubbles" ] = isSupported;
+		}
+	}
+
+	// Run tests that need a body at doc ready
+	jQuery(function() {
+		var container, div, tds, marginDiv,
+			divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
+			body = document.getElementsByTagName("body")[0];
+
+		if ( !body ) {
+			// Return for frameset docs that don't have a body
+			return;
+		}
+
+		container = document.createElement("div");
+		container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
+		body.insertBefore( container, body.firstChild );
+
+		// Construct the test element
+		div = document.createElement("div");
+		container.appendChild( div );
+
+		// Check if table cells still have offsetWidth/Height when they are set
+		// to display:none and there are still other visible table cells in a
+		// table row; if so, offsetWidth/Height are not reliable for use when
+		// determining if an element has been hidden directly using
+		// display:none (it is still safe to use offsets if a parent element is
+		// hidden; don safety goggles and see bug #4512 for more information).
+		// (only IE 8 fails this test)
+		div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+		tds = div.getElementsByTagName("td");
+		tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+		isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+		tds[ 0 ].style.display = "";
+		tds[ 1 ].style.display = "none";
+
+		// Check if empty table cells still have offsetWidth/Height
+		// (IE <= 8 fail this test)
+		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+		// Check box-sizing and margin behavior
+		div.innerHTML = "";
+		div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+		support.boxSizing = ( div.offsetWidth === 4 );
+		support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+		// NOTE: To any future maintainer, we've window.getComputedStyle
+		// because jsdom on node.js will break without it.
+		if ( window.getComputedStyle ) {
+			support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+			support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+			// Check if div with explicit width and no margin-right incorrectly
+			// gets computed margin-right based on width of container. For more
+			// info see bug #3333
+			// Fails in WebKit before Feb 2011 nightlies
+			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+			marginDiv = document.createElement("div");
+			marginDiv.style.cssText = div.style.cssText = divReset;
+			marginDiv.style.marginRight = marginDiv.style.width = "0";
+			div.style.width = "1px";
+			div.appendChild( marginDiv );
+			support.reliableMarginRight =
+				!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+		}
+
+		if ( typeof div.style.zoom !== "undefined" ) {
+			// Check if natively block-level elements act like inline-block
+			// elements when setting their display to 'inline' and giving
+			// them layout
+			// (IE < 8 does this)
+			div.innerHTML = "";
+			div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+			support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+			// Check if elements with layout shrink-wrap their children
+			// (IE 6 does this)
+			div.style.display = "block";
+			div.style.overflow = "visible";
+			div.innerHTML = "<div></div>";
+			div.firstChild.style.width = "5px";
+			support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+			container.style.zoom = 1;
+		}
+
+		// Null elements to avoid leaks in IE
+		body.removeChild( container );
+		container = div = tds = marginDiv = null;
+	});
+
+	// Null elements to avoid leaks in IE
+	fragment.removeChild( div );
+	all = a = select = opt = input = fragment = div = null;
+
+	return support;
+})();
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+	rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+	cache: {},
+
+	deletedIds: [],
+
+	// Remove at next major release (1.9/2.0)
+	uuid: 0,
+
+	// Unique for each copy of jQuery on the page
+	// Non-digits removed to match rinlinejQuery
+	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+	// The following elements throw uncatchable exceptions if you
+	// attempt to add expando properties to them.
+	noData: {
+		"embed": true,
+		// Ban all objects except for Flash (which handle expandos)
+		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+		"applet": true
+	},
+
+	hasData: function( elem ) {
+		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+		return !!elem && !isEmptyDataObject( elem );
+	},
+
+	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+		if ( !jQuery.acceptData( elem ) ) {
+			return;
+		}
+
+		var thisCache, ret,
+			internalKey = jQuery.expando,
+			getByName = typeof name === "string",
+
+			// We have to handle DOM nodes and JS objects differently because IE6-7
+			// can't GC object references properly across the DOM-JS boundary
+			isNode = elem.nodeType,
+
+			// Only DOM nodes need the global jQuery cache; JS object data is
+			// attached directly to the object so GC can occur automatically
+			cache = isNode ? jQuery.cache : elem,
+
+			// Only defining an ID for JS objects if its cache already exists allows
+			// the code to shortcut on the same path as a DOM node with no cache
+			id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+		// Avoid doing any more work than we need to when trying to get data on an
+		// object that has no data at all
+		if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+			return;
+		}
+
+		if ( !id ) {
+			// Only DOM nodes need a new unique ID for each element since their data
+			// ends up in the global cache
+			if ( isNode ) {
+				elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
+			} else {
+				id = internalKey;
+			}
+		}
+
+		if ( !cache[ id ] ) {
+			cache[ id ] = {};
+
+			// Avoids exposing jQuery metadata on plain JS objects when the object
+			// is serialized using JSON.stringify
+			if ( !isNode ) {
+				cache[ id ].toJSON = jQuery.noop;
+			}
+		}
+
+		// An object can be passed to jQuery.data instead of a key/value pair; this gets
+		// shallow copied over onto the existing cache
+		if ( typeof name === "object" || typeof name === "function" ) {
+			if ( pvt ) {
+				cache[ id ] = jQuery.extend( cache[ id ], name );
+			} else {
+				cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+			}
+		}
+
+		thisCache = cache[ id ];
+
+		// jQuery data() is stored in a separate object inside the object's internal data
+		// cache in order to avoid key collisions between internal data and user-defined
+		// data.
+		if ( !pvt ) {
+			if ( !thisCache.data ) {
+				thisCache.data = {};
+			}
+
+			thisCache = thisCache.data;
+		}
+
+		if ( data !== undefined ) {
+			thisCache[ jQuery.camelCase( name ) ] = data;
+		}
+
+		// Check for both converted-to-camel and non-converted data property names
+		// If a data property was specified
+		if ( getByName ) {
+
+			// First Try to find as-is property data
+			ret = thisCache[ name ];
+
+			// Test for null|undefined property data
+			if ( ret == null ) {
+
+				// Try to find the camelCased property
+				ret = thisCache[ jQuery.camelCase( name ) ];
+			}
+		} else {
+			ret = thisCache;
+		}
+
+		return ret;
+	},
+
+	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+		if ( !jQuery.acceptData( elem ) ) {
+			return;
+		}
+
+		var thisCache, i, l,
+
+			isNode = elem.nodeType,
+
+			// See jQuery.data for more information
+			cache = isNode ? jQuery.cache : elem,
+			id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+		// If there is already no cache entry for this object, there is no
+		// purpose in continuing
+		if ( !cache[ id ] ) {
+			return;
+		}
+
+		if ( name ) {
+
+			thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+			if ( thisCache ) {
+
+				// Support array or space separated string names for data keys
+				if ( !jQuery.isArray( name ) ) {
+
+					// try the string as a key before any manipulation
+					if ( name in thisCache ) {
+						name = [ name ];
+					} else {
+
+						// split the camel cased version by spaces unless a key with the spaces exists
+						name = jQuery.camelCase( name );
+						if ( name in thisCache ) {
+							name = [ name ];
+						} else {
+							name = name.split(" ");
+						}
+					}
+				}
+
+				for ( i = 0, l = name.length; i < l; i++ ) {
+					delete thisCache[ name[i] ];
+				}
+
+				// If there is no data left in the cache, we want to continue
+				// and let the cache object itself get destroyed
+				if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+					return;
+				}
+			}
+		}
+
+		// See jQuery.data for more information
+		if ( !pvt ) {
+			delete cache[ id ].data;
+
+			// Don't destroy the parent cache unless the internal data object
+			// had been the only thing left in it
+			if ( !isEmptyDataObject( cache[ id ] ) ) {
+				return;
+			}
+		}
+
+		// Destroy the cache
+		if ( isNode ) {
+			jQuery.cleanData( [ elem ], true );
+
+		// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+		} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+			delete cache[ id ];
+
+		// When all else fails, null
+		} else {
+			cache[ id ] = null;
+		}
+	},
+
+	// For internal use only.
+	_data: function( elem, name, data ) {
+		return jQuery.data( elem, name, data, true );
+	},
+
+	// A method for determining if a DOM node can handle the data expando
+	acceptData: function( elem ) {
+		var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+		// nodes accept data unless otherwise specified; rejection can be conditional
+		return !noData || noData !== true && elem.getAttribute("classid") === noData;
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		var parts, part, attr, name, l,
+			elem = this[0],
+			i = 0,
+			data = null;
+
+		// Gets all values
+		if ( key === undefined ) {
+			if ( this.length ) {
+				data = jQuery.data( elem );
+
+				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+					attr = elem.attributes;
+					for ( l = attr.length; i < l; i++ ) {
+						name = attr[i].name;
+
+						if ( !name.indexOf( "data-" ) ) {
+							name = jQuery.camelCase( name.substring(5) );
+
+							dataAttr( elem, name, data[ name ] );
+						}
+					}
+					jQuery._data( elem, "parsedAttrs", true );
+				}
+			}
+
+			return data;
+		}
+
+		// Sets multiple values
+		if ( typeof key === "object" ) {
+			return this.each(function() {
+				jQuery.data( this, key );
+			});
+		}
+
+		parts = key.split( ".", 2 );
+		parts[1] = parts[1] ? "." + parts[1] : "";
+		part = parts[1] + "!";
+
+		return jQuery.access( this, function( value ) {
+
+			if ( value === undefined ) {
+				data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+				// Try to fetch any internally stored data first
+				if ( data === undefined && elem ) {
+					data = jQuery.data( elem, key );
+					data = dataAttr( elem, key, data );
+				}
+
+				return data === undefined && parts[1] ?
+					this.data( parts[0] ) :
+					data;
+			}
+
+			parts[1] = value;
+			this.each(function() {
+				var self = jQuery( this );
+
+				self.triggerHandler( "setData" + part, parts );
+				jQuery.data( this, key, value );
+				self.triggerHandler( "changeData" + part, parts );
+			});
+		}, null, value, arguments.length > 1, null, false );
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			jQuery.removeData( this, key );
+		});
+	}
+});
+
+function dataAttr( elem, key, data ) {
+	// If nothing was found internally, try to fetch any
+	// data from the HTML5 data-* attribute
+	if ( data === undefined && elem.nodeType === 1 ) {
+
+		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+		data = elem.getAttribute( name );
+
+		if ( typeof data === "string" ) {
+			try {
+				data = data === "true" ? true :
+				data === "false" ? false :
+				data === "null" ? null :
+				// Only convert to a number if it doesn't change the string
+				+data + "" === data ? +data :
+				rbrace.test( data ) ? jQuery.parseJSON( data ) :
+					data;
+			} catch( e ) {}
+
+			// Make sure we set the data so it isn't changed later
+			jQuery.data( elem, key, data );
+
+		} else {
+			data = undefined;
+		}
+	}
+
+	return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+	var name;
+	for ( name in obj ) {
+
+		// if the public data object is empty, the private is still empty
+		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+			continue;
+		}
+		if ( name !== "toJSON" ) {
+			return false;
+		}
+	}
+
+	return true;
+}
+jQuery.extend({
+	queue: function( elem, type, data ) {
+		var queue;
+
+		if ( elem ) {
+			type = ( type || "fx" ) + "queue";
+			queue = jQuery._data( elem, type );
+
+			// Speed up dequeue by getting out quickly if this is just a lookup
+			if ( data ) {
+				if ( !queue || jQuery.isArray(data) ) {
+					queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+				} else {
+					queue.push( data );
+				}
+			}
+			return queue || [];
+		}
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ),
+			startLength = queue.length,
+			fn = queue.shift(),
+			hooks = jQuery._queueHooks( elem, type ),
+			next = function() {
+				jQuery.dequeue( elem, type );
+			};
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+			startLength--;
+		}
+
+		if ( fn ) {
+
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift( "inprogress" );
+			}
+
+			// clear up the last queue stop function
+			delete hooks.stop;
+			fn.call( elem, next, hooks );
+		}
+
+		if ( !startLength && hooks ) {
+			hooks.empty.fire();
+		}
+	},
+
+	// not intended for public consumption - generates a queueHooks object, or returns the current one
+	_queueHooks: function( elem, type ) {
+		var key = type + "queueHooks";
+		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+			empty: jQuery.Callbacks("once memory").add(function() {
+				jQuery.removeData( elem, type + "queue", true );
+				jQuery.removeData( elem, key, true );
+			})
+		});
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		var setter = 2;
+
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+			setter--;
+		}
+
+		if ( arguments.length < setter ) {
+			return jQuery.queue( this[0], type );
+		}
+
+		return data === undefined ?
+			this :
+			this.each(function() {
+				var queue = jQuery.queue( this, type, data );
+
+				// ensure a hooks for this queue
+				jQuery._queueHooks( this, type );
+
+				if ( type === "fx" && queue[0] !== "inprogress" ) {
+					jQuery.dequeue( this, type );
+				}
+			});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+	// Based off of the plugin by Clint Helfers, with permission.
+	// http://blindsignals.com/index.php/2009/07/jquery-delay/
+	delay: function( time, type ) {
+		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+		type = type || "fx";
+
+		return this.queue( type, function( next, hooks ) {
+			var timeout = setTimeout( next, time );
+			hooks.stop = function() {
+				clearTimeout( timeout );
+			};
+		});
+	},
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	},
+	// Get a promise resolved when queues of a certain type
+	// are emptied (fx is the type by default)
+	promise: function( type, obj ) {
+		var tmp,
+			count = 1,
+			defer = jQuery.Deferred(),
+			elements = this,
+			i = this.length,
+			resolve = function() {
+				if ( !( --count ) ) {
+					defer.resolveWith( elements, [ elements ] );
+				}
+			};
+
+		if ( typeof type !== "string" ) {
+			obj = type;
+			type = undefined;
+		}
+		type = type || "fx";
+
+		while( i-- ) {
+			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+			if ( tmp && tmp.empty ) {
+				count++;
+				tmp.empty.add( resolve );
+			}
+		}
+		resolve();
+		return defer.promise( obj );
+	}
+});
+var nodeHook, boolHook, fixSpecified,
+	rclass = /[\t\r\n]/g,
+	rreturn = /\r/g,
+	rtype = /^(?:button|input)$/i,
+	rfocusable = /^(?:button|input|object|select|textarea)$/i,
+	rclickable = /^a(?:rea|)$/i,
+	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+	getSetAttribute = jQuery.support.getSetAttribute;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+	},
+
+	removeAttr: function( name ) {
+		return this.each(function() {
+			jQuery.removeAttr( this, name );
+		});
+	},
+
+	prop: function( name, value ) {
+		return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+	},
+
+	removeProp: function( name ) {
+		name = jQuery.propFix[ name ] || name;
+		return this.each(function() {
+			// try/catch handles cases where IE balks (such as removing a property on window)
+			try {
+				this[ name ] = undefined;
+				delete this[ name ];
+			} catch( e ) {}
+		});
+	},
+
+	addClass: function( value ) {
+		var classNames, i, l, elem,
+			setClass, c, cl;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).addClass( value.call(this, j, this.className) );
+			});
+		}
+
+		if ( value && typeof value === "string" ) {
+			classNames = value.split( core_rspace );
+
+			for ( i = 0, l = this.length; i < l; i++ ) {
+				elem = this[ i ];
+
+				if ( elem.nodeType === 1 ) {
+					if ( !elem.className && classNames.length === 1 ) {
+						elem.className = value;
+
+					} else {
+						setClass = " " + elem.className + " ";
+
+						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+							if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
+								setClass += classNames[ c ] + " ";
+							}
+						}
+						elem.className = jQuery.trim( setClass );
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		var removes, className, elem, c, cl, i, l;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).removeClass( value.call(this, j, this.className) );
+			});
+		}
+		if ( (value && typeof value === "string") || value === undefined ) {
+			removes = ( value || "" ).split( core_rspace );
+
+			for ( i = 0, l = this.length; i < l; i++ ) {
+				elem = this[ i ];
+				if ( elem.nodeType === 1 && elem.className ) {
+
+					className = (" " + elem.className + " ").replace( rclass, " " );
+
+					// loop over each item in the removal list
+					for ( c = 0, cl = removes.length; c < cl; c++ ) {
+						// Remove until there is nothing to remove,
+						while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
+							className = className.replace( " " + removes[ c ] + " " , " " );
+						}
+					}
+					elem.className = value ? jQuery.trim( className ) : "";
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value,
+			isBool = typeof stateVal === "boolean";
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// toggle individual class names
+				var className,
+					i = 0,
+					self = jQuery( this ),
+					state = stateVal,
+					classNames = value.split( core_rspace );
+
+				while ( (className = classNames[ i++ ]) ) {
+					// check each className given, space separated list
+					state = isBool ? state : !self.hasClass( className );
+					self[ state ? "addClass" : "removeClass" ]( className );
+				}
+
+			} else if ( type === "undefined" || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					jQuery._data( this, "__className__", this.className );
+				}
+
+				// toggle whole className
+				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ",
+			i = 0,
+			l = this.length;
+		for ( ; i < l; i++ ) {
+			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	val: function( value ) {
+		var hooks, ret, isFunction,
+			elem = this[0];
+
+		if ( !arguments.length ) {
+			if ( elem ) {
+				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+					return ret;
+				}
+
+				ret = elem.value;
+
+				return typeof ret === "string" ?
+					// handle most common string cases
+					ret.replace(rreturn, "") :
+					// handle cases where value is null/undef or number
+					ret == null ? "" : ret;
+			}
+
+			return;
+		}
+
+		isFunction = jQuery.isFunction( value );
+
+		return this.each(function( i ) {
+			var val,
+				self = jQuery(this);
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call( this, i, self.val() );
+			} else {
+				val = value;
+			}
+
+			// Treat null/undefined as ""; convert numbers to string
+			if ( val == null ) {
+				val = "";
+			} else if ( typeof val === "number" ) {
+				val += "";
+			} else if ( jQuery.isArray( val ) ) {
+				val = jQuery.map(val, function ( value ) {
+					return value == null ? "" : value + "";
+				});
+			}
+
+			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+			// If set returns undefined, fall back to normal setting
+			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	valHooks: {
+		option: {
+			get: function( elem ) {
+				// attributes.value is undefined in Blackberry 4.7 but
+				// uses .value. See #6932
+				var val = elem.attributes.value;
+				return !val || val.specified ? elem.value : elem.text;
+			}
+		},
+		select: {
+			get: function( elem ) {
+				var value, option,
+					options = elem.options,
+					index = elem.selectedIndex,
+					one = elem.type === "select-one" || index < 0,
+					values = one ? null : [],
+					max = one ? index + 1 : options.length,
+					i = index < 0 ?
+						max :
+						one ? index : 0;
+
+				// Loop through all the selected options
+				for ( ; i < max; i++ ) {
+					option = options[ i ];
+
+					// oldIE doesn't update selected after form reset (#2551)
+					if ( ( option.selected || i === index ) &&
+							// Don't return options that are disabled or in a disabled optgroup
+							( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+						// Get the specific value for the option
+						value = jQuery( option ).val();
+
+						// We don't need an array for one selects
+						if ( one ) {
+							return value;
+						}
+
+						// Multi-Selects return an array
+						values.push( value );
+					}
+				}
+
+				return values;
+			},
+
+			set: function( elem, value ) {
+				var values = jQuery.makeArray( value );
+
+				jQuery(elem).find("option").each(function() {
+					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+				});
+
+				if ( !values.length ) {
+					elem.selectedIndex = -1;
+				}
+				return values;
+			}
+		}
+	},
+
+	// Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
+	attrFn: {},
+
+	attr: function( elem, name, value, pass ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set attributes on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
+			return jQuery( elem )[ name ]( value );
+		}
+
+		// Fallback to prop when attributes are not supported
+		if ( typeof elem.getAttribute === "undefined" ) {
+			return jQuery.prop( elem, name, value );
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		// All attributes are lowercase
+		// Grab necessary hook if one is defined
+		if ( notxml ) {
+			name = name.toLowerCase();
+			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+		}
+
+		if ( value !== undefined ) {
+
+			if ( value === null ) {
+				jQuery.removeAttr( elem, name );
+				return;
+
+			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				elem.setAttribute( name, value + "" );
+				return value;
+			}
+
+		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+			return ret;
+
+		} else {
+
+			ret = elem.getAttribute( name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return ret === null ?
+				undefined :
+				ret;
+		}
+	},
+
+	removeAttr: function( elem, value ) {
+		var propName, attrNames, name, isBool,
+			i = 0;
+
+		if ( value && elem.nodeType === 1 ) {
+
+			attrNames = value.split( core_rspace );
+
+			for ( ; i < attrNames.length; i++ ) {
+				name = attrNames[ i ];
+
+				if ( name ) {
+					propName = jQuery.propFix[ name ] || name;
+					isBool = rboolean.test( name );
+
+					// See #9699 for explanation of this approach (setting first, then removal)
+					// Do not do this for boolean attributes (see #10870)
+					if ( !isBool ) {
+						jQuery.attr( elem, name, "" );
+					}
+					elem.removeAttribute( getSetAttribute ? name : propName );
+
+					// Set corresponding property to false for boolean attributes
+					if ( isBool && propName in elem ) {
+						elem[ propName ] = false;
+					}
+				}
+			}
+		}
+	},
+
+	attrHooks: {
+		type: {
+			set: function( elem, value ) {
+				// We can't allow the type property to be changed (since it causes problems in IE)
+				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+					jQuery.error( "type property can't be changed" );
+				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+					// Setting the type on a radio button after the value resets the value in IE6-9
+					// Reset value to it's default in case type is set after value
+					// This is for element creation
+					var val = elem.value;
+					elem.setAttribute( "type", value );
+					if ( val ) {
+						elem.value = val;
+					}
+					return value;
+				}
+			}
+		},
+		// Use the value property for back compat
+		// Use the nodeHook for button elements in IE6/7 (#1954)
+		value: {
+			get: function( elem, name ) {
+				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+					return nodeHook.get( elem, name );
+				}
+				return name in elem ?
+					elem.value :
+					null;
+			},
+			set: function( elem, value, name ) {
+				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+					return nodeHook.set( elem, value, name );
+				}
+				// Does not return so that setAttribute is also used
+				elem.value = value;
+			}
+		}
+	},
+
+	propFix: {
+		tabindex: "tabIndex",
+		readonly: "readOnly",
+		"for": "htmlFor",
+		"class": "className",
+		maxlength: "maxLength",
+		cellspacing: "cellSpacing",
+		cellpadding: "cellPadding",
+		rowspan: "rowSpan",
+		colspan: "colSpan",
+		usemap: "useMap",
+		frameborder: "frameBorder",
+		contenteditable: "contentEditable"
+	},
+
+	prop: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set properties on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		if ( notxml ) {
+			// Fix name and attach hooks
+			name = jQuery.propFix[ name ] || name;
+			hooks = jQuery.propHooks[ name ];
+		}
+
+		if ( value !== undefined ) {
+			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				return ( elem[ name ] = value );
+			}
+
+		} else {
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+				return ret;
+
+			} else {
+				return elem[ name ];
+			}
+		}
+	},
+
+	propHooks: {
+		tabIndex: {
+			get: function( elem ) {
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				var attributeNode = elem.getAttributeNode("tabindex");
+
+				return attributeNode && attributeNode.specified ?
+					parseInt( attributeNode.value, 10 ) :
+					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+						0 :
+						undefined;
+			}
+		}
+	}
+});
+
+// Hook for boolean attributes
+boolHook = {
+	get: function( elem, name ) {
+		// Align boolean attributes with corresponding properties
+		// Fall back to attribute presence where some booleans are not supported
+		var attrNode,
+			property = jQuery.prop( elem, name );
+		return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+			name.toLowerCase() :
+			undefined;
+	},
+	set: function( elem, value, name ) {
+		var propName;
+		if ( value === false ) {
+			// Remove boolean attributes when set to false
+			jQuery.removeAttr( elem, name );
+		} else {
+			// value is true since we know at this point it's type boolean and not false
+			// Set boolean attributes to the same name and set the DOM property
+			propName = jQuery.propFix[ name ] || name;
+			if ( propName in elem ) {
+				// Only set the IDL specifically if it already exists on the element
+				elem[ propName ] = true;
+			}
+
+			elem.setAttribute( name, name.toLowerCase() );
+		}
+		return name;
+	}
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+	fixSpecified = {
+		name: true,
+		id: true,
+		coords: true
+	};
+
+	// Use this for any attribute in IE6/7
+	// This fixes almost every IE6/7 issue
+	nodeHook = jQuery.valHooks.button = {
+		get: function( elem, name ) {
+			var ret;
+			ret = elem.getAttributeNode( name );
+			return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
+				ret.value :
+				undefined;
+		},
+		set: function( elem, value, name ) {
+			// Set the existing or create a new attribute node
+			var ret = elem.getAttributeNode( name );
+			if ( !ret ) {
+				ret = document.createAttribute( name );
+				elem.setAttributeNode( ret );
+			}
+			return ( ret.value = value + "" );
+		}
+	};
+
+	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
+	// This is for removals
+	jQuery.each([ "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			set: function( elem, value ) {
+				if ( value === "" ) {
+					elem.setAttribute( name, "auto" );
+					return value;
+				}
+			}
+		});
+	});
+
+	// Set contenteditable to false on removals(#10429)
+	// Setting to empty string throws an error as an invalid value
+	jQuery.attrHooks.contenteditable = {
+		get: nodeHook.get,
+		set: function( elem, value, name ) {
+			if ( value === "" ) {
+				value = "false";
+			}
+			nodeHook.set( elem, value, name );
+		}
+	};
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			get: function( elem ) {
+				var ret = elem.getAttribute( name, 2 );
+				return ret === null ? undefined : ret;
+			}
+		});
+	});
+}
+
+if ( !jQuery.support.style ) {
+	jQuery.attrHooks.style = {
+		get: function( elem ) {
+			// Return undefined in the case of empty string
+			// Normalize to lowercase since IE uppercases css property names
+			return elem.style.cssText.toLowerCase() || undefined;
+		},
+		set: function( elem, value ) {
+			return ( elem.style.cssText = value + "" );
+		}
+	};
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+		get: function( elem ) {
+			var parent = elem.parentNode;
+
+			if ( parent ) {
+				parent.selectedIndex;
+
+				// Make sure that it also works with optgroups, see #5701
+				if ( parent.parentNode ) {
+					parent.parentNode.selectedIndex;
+				}
+			}
+			return null;
+		}
+	});
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+	jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+	jQuery.each([ "radio", "checkbox" ], function() {
+		jQuery.valHooks[ this ] = {
+			get: function( elem ) {
+				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+				return elem.getAttribute("value") === null ? "on" : elem.value;
+			}
+		};
+	});
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+		set: function( elem, value ) {
+			if ( jQuery.isArray( value ) ) {
+				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+			}
+		}
+	});
+});
+var rformElems = /^(?:textarea|input|select)$/i,
+	rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
+	rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+	rkeyEvent = /^key/,
+	rmouseEvent = /^(?:mouse|contextmenu)|click/,
+	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+	hoverHack = function( events ) {
+		return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+	};
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+	add: function( elem, types, handler, data, selector ) {
+
+		var elemData, eventHandle, events,
+			t, tns, type, namespaces, handleObj,
+			handleObjIn, handlers, special;
+
+		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
+		if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+			return;
+		}
+
+		// Caller can pass in an object of custom data in lieu of the handler
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+			selector = handleObjIn.selector;
+		}
+
+		// Make sure that the handler has a unique ID, used to find/remove it later
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure and main handler, if this is the first
+		events = elemData.events;
+		if ( !events ) {
+			elemData.events = events = {};
+		}
+		eventHandle = elemData.handle;
+		if ( !eventHandle ) {
+			elemData.handle = eventHandle = function( e ) {
+				// Discard the second event of a jQuery.event.trigger() and
+				// when an event is called after a page has unloaded
+				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+					undefined;
+			};
+			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+			eventHandle.elem = elem;
+		}
+
+		// Handle multiple events separated by a space
+		// jQuery(...).bind("mouseover mouseout", fn);
+		types = jQuery.trim( hoverHack(types) ).split( " " );
+		for ( t = 0; t < types.length; t++ ) {
+
+			tns = rtypenamespace.exec( types[t] ) || [];
+			type = tns[1];
+			namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+			// If event changes its type, use the special event handlers for the changed type
+			special = jQuery.event.special[ type ] || {};
+
+			// If selector defined, determine special event api type, otherwise given type
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+
+			// Update special based on newly reset type
+			special = jQuery.event.special[ type ] || {};
+
+			// handleObj is passed to all event handlers
+			handleObj = jQuery.extend({
+				type: type,
+				origType: tns[1],
+				data: data,
+				handler: handler,
+				guid: handler.guid,
+				selector: selector,
+				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+				namespace: namespaces.join(".")
+			}, handleObjIn );
+
+			// Init the event handler queue if we're the first
+			handlers = events[ type ];
+			if ( !handlers ) {
+				handlers = events[ type ] = [];
+				handlers.delegateCount = 0;
+
+				// Only use addEventListener/attachEvent if the special events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					// Bind the global event handler to the element
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+
+					} else if ( elem.attachEvent ) {
+						elem.attachEvent( "on" + type, eventHandle );
+					}
+				}
+			}
+
+			if ( special.add ) {
+				special.add.call( elem, handleObj );
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add to the element's handler list, delegates in front
+			if ( selector ) {
+				handlers.splice( handlers.delegateCount++, 0, handleObj );
+			} else {
+				handlers.push( handleObj );
+			}
+
+			// Keep track of which events have ever been used, for event optimization
+			jQuery.event.global[ type ] = true;
+		}
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	global: {},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, selector, mappedTypes ) {
+
+		var t, tns, type, origType, namespaces, origCount,
+			j, events, special, eventType, handleObj,
+			elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+		if ( !elemData || !(events = elemData.events) ) {
+			return;
+		}
+
+		// Once for each type.namespace in types; type may be omitted
+		types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+		for ( t = 0; t < types.length; t++ ) {
+			tns = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tns[1];
+			namespaces = tns[2];
+
+			// Unbind all events (on this namespace, if provided) for the element
+			if ( !type ) {
+				for ( type in events ) {
+					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+				}
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+			type = ( selector? special.delegateType : special.bindType ) || type;
+			eventType = events[ type ] || [];
+			origCount = eventType.length;
+			namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+
+			// Remove matching events
+			for ( j = 0; j < eventType.length; j++ ) {
+				handleObj = eventType[ j ];
+
+				if ( ( mappedTypes || origType === handleObj.origType ) &&
+					 ( !handler || handler.guid === handleObj.guid ) &&
+					 ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+					 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+					eventType.splice( j--, 1 );
+
+					if ( handleObj.selector ) {
+						eventType.delegateCount--;
+					}
+					if ( special.remove ) {
+						special.remove.call( elem, handleObj );
+					}
+				}
+			}
+
+			// Remove generic event handler if we removed something and no more handlers exist
+			// (avoids potential for endless recursion during removal of special event handlers)
+			if ( eventType.length === 0 && origCount !== eventType.length ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+					jQuery.removeEvent( elem, type, elemData.handle );
+				}
+
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			delete elemData.handle;
+
+			// removeData also checks for emptiness and clears the expando if empty
+			// so use it instead of delete
+			jQuery.removeData( elem, "events", true );
+		}
+	},
+
+	// Events that are safe to short-circuit if no handlers are attached.
+	// Native DOM events should not be added, they may have inline handlers.
+	customEvent: {
+		"getData": true,
+		"setData": true,
+		"changeData": true
+	},
+
+	trigger: function( event, data, elem, onlyHandlers ) {
+		// Don't do events on text and comment nodes
+		if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+			return;
+		}
+
+		// Event object or event type
+		var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
+			type = event.type || event,
+			namespaces = [];
+
+		// focus/blur morphs to focusin/out; ensure we're not firing them right now
+		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+			return;
+		}
+
+		if ( type.indexOf( "!" ) >= 0 ) {
+			// Exclusive events trigger only for the exact event (no namespaces)
+			type = type.slice(0, -1);
+			exclusive = true;
+		}
+
+		if ( type.indexOf( "." ) >= 0 ) {
+			// Namespaced trigger; create a regexp to match event type in handle()
+			namespaces = type.split(".");
+			type = namespaces.shift();
+			namespaces.sort();
+		}
+
+		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+			// No jQuery handlers for this event type, and it can't have inline handlers
+			return;
+		}
+
+		// Caller can pass in an Event, Object, or just an event type string
+		event = typeof event === "object" ?
+			// jQuery.Event object
+			event[ jQuery.expando ] ? event :
+			// Object literal
+			new jQuery.Event( type, event ) :
+			// Just the event type (string)
+			new jQuery.Event( type );
+
+		event.type = type;
+		event.isTrigger = true;
+		event.exclusive = exclusive;
+		event.namespace = namespaces.join( "." );
+		event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
+		ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+		// Handle a global trigger
+		if ( !elem ) {
+
+			// TODO: Stop taunting the data cache; remove global events and always attach to document
+			cache = jQuery.cache;
+			for ( i in cache ) {
+				if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+					jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+				}
+			}
+			return;
+		}
+
+		// Clean up the event in case it is being reused
+		event.result = undefined;
+		if ( !event.target ) {
+			event.target = elem;
+		}
+
+		// Clone any incoming data and prepend the event, creating the handler arg list
+		data = data != null ? jQuery.makeArray( data ) : [];
+		data.unshift( event );
+
+		// Allow special events to draw outside the lines
+		special = jQuery.event.special[ type ] || {};
+		if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+			return;
+		}
+
+		// Determine event propagation path in advance, per W3C events spec (#9951)
+		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+		eventPath = [[ elem, special.bindType || type ]];
+		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+			bubbleType = special.delegateType || type;
+			cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+			for ( old = elem; cur; cur = cur.parentNode ) {
+				eventPath.push([ cur, bubbleType ]);
+				old = cur;
+			}
+
+			// Only add window if we got to document (e.g., not plain obj or detached DOM)
+			if ( old === (elem.ownerDocument || document) ) {
+				eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+			}
+		}
+
+		// Fire handlers on the event path
+		for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+			cur = eventPath[i][0];
+			event.type = eventPath[i][1];
+
+			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+			if ( handle ) {
+				handle.apply( cur, data );
+			}
+			// Note that this is a bare JS function and not a jQuery handler
+			handle = ontype && cur[ ontype ];
+			if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+				event.preventDefault();
+			}
+		}
+		event.type = type;
+
+		// If nobody prevented the default action, do it now
+		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+				// Call a native DOM method on the target with the same name name as the event.
+				// Can't use an .isFunction() check here because IE6/7 fails that test.
+				// Don't do default actions on window, that's where global variables be (#6170)
+				// IE<9 dies on focus/blur to hidden element (#1486)
+				if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+					// Don't re-trigger an onFOO event when we call its FOO() method
+					old = elem[ ontype ];
+
+					if ( old ) {
+						elem[ ontype ] = null;
+					}
+
+					// Prevent re-triggering of the same event, since we already bubbled it above
+					jQuery.event.triggered = type;
+					elem[ type ]();
+					jQuery.event.triggered = undefined;
+
+					if ( old ) {
+						elem[ ontype ] = old;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	dispatch: function( event ) {
+
+		// Make a writable jQuery.Event from the native event object
+		event = jQuery.event.fix( event || window.event );
+
+		var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
+			handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+			delegateCount = handlers.delegateCount,
+			args = core_slice.call( arguments ),
+			run_all = !event.exclusive && !event.namespace,
+			special = jQuery.event.special[ event.type ] || {},
+			handlerQueue = [];
+
+		// Use the fix-ed jQuery.Event rather than the (read-only) native event
+		args[0] = event;
+		event.delegateTarget = this;
+
+		// Call the preDispatch hook for the mapped type, and let it bail if desired
+		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+			return;
+		}
+
+		// Determine handlers that should run if there are delegated events
+		// Avoid non-left-click bubbling in Firefox (#3861)
+		if ( delegateCount && !(event.button && event.type === "click") ) {
+
+			for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+				// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
+				if ( cur.disabled !== true || event.type !== "click" ) {
+					selMatch = {};
+					matches = [];
+					for ( i = 0; i < delegateCount; i++ ) {
+						handleObj = handlers[ i ];
+						sel = handleObj.selector;
+
+						if ( selMatch[ sel ] === undefined ) {
+							selMatch[ sel ] = handleObj.needsContext ?
+								jQuery( sel, this ).index( cur ) >= 0 :
+								jQuery.find( sel, this, null, [ cur ] ).length;
+						}
+						if ( selMatch[ sel ] ) {
+							matches.push( handleObj );
+						}
+					}
+					if ( matches.length ) {
+						handlerQueue.push({ elem: cur, matches: matches });
+					}
+				}
+			}
+		}
+
+		// Add the remaining (directly-bound) handlers
+		if ( handlers.length > delegateCount ) {
+			handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+		}
+
+		// Run delegates first; they may want to stop propagation beneath us
+		for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+			matched = handlerQueue[ i ];
+			event.currentTarget = matched.elem;
+
+			for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+				handleObj = matched.matches[ j ];
+
+				// Triggered event must either 1) be non-exclusive and have no namespace, or
+				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+				if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+					event.data = handleObj.data;
+					event.handleObj = handleObj;
+
+					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+							.apply( matched.elem, args );
+
+					if ( ret !== undefined ) {
+						event.result = ret;
+						if ( ret === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+				}
+			}
+		}
+
+		// Call the postDispatch hook for the mapped type
+		if ( special.postDispatch ) {
+			special.postDispatch.call( this, event );
+		}
+
+		return event.result;
+	},
+
+	// Includes some event props shared by KeyEvent and MouseEvent
+	// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+	props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+	fixHooks: {},
+
+	keyHooks: {
+		props: "char charCode key keyCode".split(" "),
+		filter: function( event, original ) {
+
+			// Add which for key events
+			if ( event.which == null ) {
+				event.which = original.charCode != null ? original.charCode : original.keyCode;
+			}
+
+			return event;
+		}
+	},
+
+	mouseHooks: {
+		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+		filter: function( event, original ) {
+			var eventDoc, doc, body,
+				button = original.button,
+				fromElement = original.fromElement;
+
+			// Calculate pageX/Y if missing and clientX/Y available
+			if ( event.pageX == null && original.clientX != null ) {
+				eventDoc = event.target.ownerDocument || document;
+				doc = eventDoc.documentElement;
+				body = eventDoc.body;
+
+				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+			}
+
+			// Add relatedTarget, if necessary
+			if ( !event.relatedTarget && fromElement ) {
+				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+			}
+
+			// Add which for click: 1 === left; 2 === middle; 3 === right
+			// Note: button is not normalized, so don't use it
+			if ( !event.which && button !== undefined ) {
+				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+			}
+
+			return event;
+		}
+	},
+
+	fix: function( event ) {
+		if ( event[ jQuery.expando ] ) {
+			return event;
+		}
+
+		// Create a writable copy of the event object and normalize some properties
+		var i, prop,
+			originalEvent = event,
+			fixHook = jQuery.event.fixHooks[ event.type ] || {},
+			copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+		event = jQuery.Event( originalEvent );
+
+		for ( i = copy.length; i; ) {
+			prop = copy[ --i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+		if ( !event.target ) {
+			event.target = originalEvent.srcElement || document;
+		}
+
+		// Target should not be a text node (#504, Safari)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
+		event.metaKey = !!event.metaKey;
+
+		return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+	},
+
+	special: {
+		load: {
+			// Prevent triggered image.load events from bubbling to window.load
+			noBubble: true
+		},
+
+		focus: {
+			delegateType: "focusin"
+		},
+		blur: {
+			delegateType: "focusout"
+		},
+
+		beforeunload: {
+			setup: function( data, namespaces, eventHandle ) {
+				// We only want to do this special case on windows
+				if ( jQuery.isWindow( this ) ) {
+					this.onbeforeunload = eventHandle;
+				}
+			},
+
+			teardown: function( namespaces, eventHandle ) {
+				if ( this.onbeforeunload === eventHandle ) {
+					this.onbeforeunload = null;
+				}
+			}
+		}
+	},
+
+	simulate: function( type, elem, event, bubble ) {
+		// Piggyback on a donor event to simulate a different one.
+		// Fake originalEvent to avoid donor's stopPropagation, but if the
+		// simulated event prevents default then we do the same on the donor.
+		var e = jQuery.extend(
+			new jQuery.Event(),
+			event,
+			{ type: type,
+				isSimulated: true,
+				originalEvent: {}
+			}
+		);
+		if ( bubble ) {
+			jQuery.event.trigger( e, null, elem );
+		} else {
+			jQuery.event.dispatch.call( elem, e );
+		}
+		if ( e.isDefaultPrevented() ) {
+			event.preventDefault();
+		}
+	}
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+	function( elem, type, handle ) {
+		if ( elem.removeEventListener ) {
+			elem.removeEventListener( type, handle, false );
+		}
+	} :
+	function( elem, type, handle ) {
+		var name = "on" + type;
+
+		if ( elem.detachEvent ) {
+
+			// #8545, #7054, preventing memory leaks for custom events in IE6-8
+			// detachEvent needed property on element, by name of that event, to properly expose it to GC
+			if ( typeof elem[ name ] === "undefined" ) {
+				elem[ name ] = null;
+			}
+
+			elem.detachEvent( name, handle );
+		}
+	};
+
+jQuery.Event = function( src, props ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !(this instanceof jQuery.Event) ) {
+		return new jQuery.Event( src, props );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+
+		// Events bubbling up the document may have been marked as prevented
+		// by a handler lower down the tree; reflect the correct value.
+		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// Put explicitly provided properties onto the event object
+	if ( props ) {
+		jQuery.extend( this, props );
+	}
+
+	// Create a timestamp if incoming event doesn't have one
+	this.timeStamp = src && src.timeStamp || jQuery.now();
+
+	// Mark it as fixed
+	this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+	return false;
+}
+function returnTrue() {
+	return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	preventDefault: function() {
+		this.isDefaultPrevented = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+
+		// if preventDefault exists run it on the original event
+		if ( e.preventDefault ) {
+			e.preventDefault();
+
+		// otherwise set the returnValue property of the original event to false (IE)
+		} else {
+			e.returnValue = false;
+		}
+	},
+	stopPropagation: function() {
+		this.isPropagationStopped = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+		// if stopPropagation exists run it on the original event
+		if ( e.stopPropagation ) {
+			e.stopPropagation();
+		}
+		// otherwise set the cancelBubble property of the original event to true (IE)
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation: function() {
+		this.isImmediatePropagationStopped = returnTrue;
+		this.stopPropagation();
+	},
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		delegateType: fix,
+		bindType: fix,
+
+		handle: function( event ) {
+			var ret,
+				target = this,
+				related = event.relatedTarget,
+				handleObj = event.handleObj,
+				selector = handleObj.selector;
+
+			// For mousenter/leave call the handler if related is outside the target.
+			// NB: No relatedTarget if the mouse left/entered the browser window
+			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+				event.type = handleObj.origType;
+				ret = handleObj.handler.apply( this, arguments );
+				event.type = fix;
+			}
+			return ret;
+		}
+	};
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+	jQuery.event.special.submit = {
+		setup: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Lazy-add a submit handler when a descendant form may potentially be submitted
+			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+				// Node name check avoids a VML-related crash in IE (#9807)
+				var elem = e.target,
+					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+				if ( form && !jQuery._data( form, "_submit_attached" ) ) {
+					jQuery.event.add( form, "submit._submit", function( event ) {
+						event._submit_bubble = true;
+					});
+					jQuery._data( form, "_submit_attached", true );
+				}
+			});
+			// return undefined since we don't need an event listener
+		},
+
+		postDispatch: function( event ) {
+			// If form was submitted by the user, bubble the event up the tree
+			if ( event._submit_bubble ) {
+				delete event._submit_bubble;
+				if ( this.parentNode && !event.isTrigger ) {
+					jQuery.event.simulate( "submit", this.parentNode, event, true );
+				}
+			}
+		},
+
+		teardown: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+			jQuery.event.remove( this, "._submit" );
+		}
+	};
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+	jQuery.event.special.change = {
+
+		setup: function() {
+
+			if ( rformElems.test( this.nodeName ) ) {
+				// IE doesn't fire change on a check/radio until blur; trigger it on click
+				// after a propertychange. Eat the blur-change in special.change.handle.
+				// This still fires onchange a second time for check/radio after blur.
+				if ( this.type === "checkbox" || this.type === "radio" ) {
+					jQuery.event.add( this, "propertychange._change", function( event ) {
+						if ( event.originalEvent.propertyName === "checked" ) {
+							this._just_changed = true;
+						}
+					});
+					jQuery.event.add( this, "click._change", function( event ) {
+						if ( this._just_changed && !event.isTrigger ) {
+							this._just_changed = false;
+						}
+						// Allow triggered, simulated change events (#11500)
+						jQuery.event.simulate( "change", this, event, true );
+					});
+				}
+				return false;
+			}
+			// Delegated event; lazy-add a change handler on descendant inputs
+			jQuery.event.add( this, "beforeactivate._change", function( e ) {
+				var elem = e.target;
+
+				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
+					jQuery.event.add( elem, "change._change", function( event ) {
+						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+							jQuery.event.simulate( "change", this.parentNode, event, true );
+						}
+					});
+					jQuery._data( elem, "_change_attached", true );
+				}
+			});
+		},
+
+		handle: function( event ) {
+			var elem = event.target;
+
+			// Swallow native change events from checkbox/radio, we already triggered them above
+			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+				return event.handleObj.handler.apply( this, arguments );
+			}
+		},
+
+		teardown: function() {
+			jQuery.event.remove( this, "._change" );
+
+			return !rformElems.test( this.nodeName );
+		}
+	};
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+		// Attach a single capturing handler while someone wants focusin/focusout
+		var attaches = 0,
+			handler = function( event ) {
+				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+			};
+
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				if ( attaches++ === 0 ) {
+					document.addEventListener( orig, handler, true );
+				}
+			},
+			teardown: function() {
+				if ( --attaches === 0 ) {
+					document.removeEventListener( orig, handler, true );
+				}
+			}
+		};
+	});
+}
+
+jQuery.fn.extend({
+
+	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+		var origFn, type;
+
+		// Types can be a map of types/handlers
+		if ( typeof types === "object" ) {
+			// ( types-Object, selector, data )
+			if ( typeof selector !== "string" ) { // && selector != null
+				// ( types-Object, data )
+				data = data || selector;
+				selector = undefined;
+			}
+			for ( type in types ) {
+				this.on( type, selector, data, types[ type ], one );
+			}
+			return this;
+		}
+
+		if ( data == null && fn == null ) {
+			// ( types, fn )
+			fn = selector;
+			data = selector = undefined;
+		} else if ( fn == null ) {
+			if ( typeof selector === "string" ) {
+				// ( types, selector, fn )
+				fn = data;
+				data = undefined;
+			} else {
+				// ( types, data, fn )
+				fn = data;
+				data = selector;
+				selector = undefined;
+			}
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		} else if ( !fn ) {
+			return this;
+		}
+
+		if ( one === 1 ) {
+			origFn = fn;
+			fn = function( event ) {
+				// Can use an empty set, since event contains the info
+				jQuery().off( event );
+				return origFn.apply( this, arguments );
+			};
+			// Use same guid so caller can remove using origFn
+			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+		}
+		return this.each( function() {
+			jQuery.event.add( this, types, fn, data, selector );
+		});
+	},
+	one: function( types, selector, data, fn ) {
+		return this.on( types, selector, data, fn, 1 );
+	},
+	off: function( types, selector, fn ) {
+		var handleObj, type;
+		if ( types && types.preventDefault && types.handleObj ) {
+			// ( event )  dispatched jQuery.Event
+			handleObj = types.handleObj;
+			jQuery( types.delegateTarget ).off(
+				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+				handleObj.selector,
+				handleObj.handler
+			);
+			return this;
+		}
+		if ( typeof types === "object" ) {
+			// ( types-object [, selector] )
+			for ( type in types ) {
+				this.off( type, selector, types[ type ] );
+			}
+			return this;
+		}
+		if ( selector === false || typeof selector === "function" ) {
+			// ( types [, fn] )
+			fn = selector;
+			selector = undefined;
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		}
+		return this.each(function() {
+			jQuery.event.remove( this, types, fn, selector );
+		});
+	},
+
+	bind: function( types, data, fn ) {
+		return this.on( types, null, data, fn );
+	},
+	unbind: function( types, fn ) {
+		return this.off( types, null, fn );
+	},
+
+	live: function( types, data, fn ) {
+		jQuery( this.context ).on( types, this.selector, data, fn );
+		return this;
+	},
+	die: function( types, fn ) {
+		jQuery( this.context ).off( types, this.selector || "**", fn );
+		return this;
+	},
+
+	delegate: function( selector, types, data, fn ) {
+		return this.on( types, selector, data, fn );
+	},
+	undelegate: function( selector, types, fn ) {
+		// ( namespace ) or ( selector, types [, fn] )
+		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+	triggerHandler: function( type, data ) {
+		if ( this[0] ) {
+			return jQuery.event.trigger( type, data, this[0], true );
+		}
+	},
+
+	toggle: function( fn ) {
+		// Save reference to arguments for access in closure
+		var args = arguments,
+			guid = fn.guid || jQuery.guid++,
+			i = 0,
+			toggler = function( event ) {
+				// Figure out which function to execute
+				var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+				jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+				// Make sure that clicks stop
+				event.preventDefault();
+
+				// and execute the function
+				return args[ lastToggle ].apply( this, arguments ) || false;
+			};
+
+		// link all the functions, so any of them can unbind this click handler
+		toggler.guid = guid;
+		while ( i < args.length ) {
+			args[ i++ ].guid = guid;
+		}
+
+		return this.click( toggler );
+	},
+
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	}
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( data, fn ) {
+		if ( fn == null ) {
+			fn = data;
+			data = null;
+		}
+
+		return arguments.length > 0 ?
+			this.on( name, null, data, fn ) :
+			this.trigger( name );
+	};
+
+	if ( rkeyEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+	}
+
+	if ( rmouseEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+	}
+});
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var cachedruns,
+	assertGetIdNotName,
+	Expr,
+	getText,
+	isXML,
+	contains,
+	compile,
+	sortOrder,
+	hasDuplicate,
+	outermostContext,
+
+	baseHasDuplicate = true,
+	strundefined = "undefined",
+
+	expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
+
+	Token = String,
+	document = window.document,
+	docElem = document.documentElement,
+	dirruns = 0,
+	done = 0,
+	pop = [].pop,
+	push = [].push,
+	slice = [].slice,
+	// Use a stripped-down indexOf if a native one is unavailable
+	indexOf = [].indexOf || function( elem ) {
+		var i = 0,
+			len = this.length;
+		for ( ; i < len; i++ ) {
+			if ( this[i] === elem ) {
+				return i;
+			}
+		}
+		return -1;
+	},
+
+	// Augment a function for special use by Sizzle
+	markFunction = function( fn, value ) {
+		fn[ expando ] = value == null || value;
+		return fn;
+	},
+
+	createCache = function() {
+		var cache = {},
+			keys = [];
+
+		return markFunction(function( key, value ) {
+			// Only keep the most recent entries
+			if ( keys.push( key ) > Expr.cacheLength ) {
+				delete cache[ keys.shift() ];
+			}
+
+			// Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157)
+			return (cache[ key + " " ] = value);
+		}, cache );
+	},
+
+	classCache = createCache(),
+	tokenCache = createCache(),
+	compilerCache = createCache(),
+
+	// Regex
+
+	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+	whitespace = "[\\x20\\t\\r\\n\\f]",
+	// http://www.w3.org/TR/css3-syntax/#characters
+	characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
+
+	// Loosely modeled on CSS identifier characters
+	// An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
+	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+	identifier = characterEncoding.replace( "w", "w#" ),
+
+	// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+	operators = "([*^$|!~]?=)",
+	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+		"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+	// Prefer arguments not in parens/brackets,
+	//   then attribute selectors and non-pseudos (denoted by :),
+	//   then anything else
+	// These preferences are here to reduce the number of selectors
+	//   needing tokenize in the PSEUDO preFilter
+	pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
+
+	// For matchExpr.POS and matchExpr.needsContext
+	pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+		"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
+
+	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+	rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+	rpseudo = new RegExp( pseudos ),
+
+	// Easily-parseable/retrievable ID or TAG or CLASS selectors
+	rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
+
+	rnot = /^:not/,
+	rsibling = /[\x20\t\r\n\f]*[+~]/,
+	rendsWithNot = /:not\($/,
+
+	rheader = /h\d/i,
+	rinputs = /input|select|textarea|button/i,
+
+	rbackslash = /\\(?!\\)/g,
+
+	matchExpr = {
+		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
+		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+		"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+		"ATTR": new RegExp( "^" + attributes ),
+		"PSEUDO": new RegExp( "^" + pseudos ),
+		"POS": new RegExp( pos, "i" ),
+		"CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
+			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+		// For use in libraries implementing .is()
+		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
+	},
+
+	// Support
+
+	// Used for testing something on an element
+	assert = function( fn ) {
+		var div = document.createElement("div");
+
+		try {
+			return fn( div );
+		} catch (e) {
+			return false;
+		} finally {
+			// release memory in IE
+			div = null;
+		}
+	},
+
+	// Check if getElementsByTagName("*") returns only elements
+	assertTagNameNoComments = assert(function( div ) {
+		div.appendChild( document.createComment("") );
+		return !div.getElementsByTagName("*").length;
+	}),
+
+	// Check if getAttribute returns normalized href attributes
+	assertHrefNotNormalized = assert(function( div ) {
+		div.innerHTML = "<a href='#'></a>";
+		return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+			div.firstChild.getAttribute("href") === "#";
+	}),
+
+	// Check if attributes should be retrieved by attribute nodes
+	assertAttributes = assert(function( div ) {
+		div.innerHTML = "<select></select>";
+		var type = typeof div.lastChild.getAttribute("multiple");
+		// IE8 returns a string for some attributes even when not present
+		return type !== "boolean" && type !== "string";
+	}),
+
+	// Check if getElementsByClassName can be trusted
+	assertUsableClassName = assert(function( div ) {
+		// Opera can't find a second classname (in 9.6)
+		div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
+		if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+			return false;
+		}
+
+		// Safari 3.2 caches class attributes and doesn't catch changes
+		div.lastChild.className = "e";
+		return div.getElementsByClassName("e").length === 2;
+	}),
+
+	// Check if getElementById returns elements by name
+	// Check if getElementsByName privileges form controls or returns elements by ID
+	assertUsableName = assert(function( div ) {
+		// Inject content
+		div.id = expando + 0;
+		div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
+		docElem.insertBefore( div, docElem.firstChild );
+
+		// Test
+		var pass = document.getElementsByName &&
+			// buggy browsers will return fewer than the correct 2
+			document.getElementsByName( expando ).length === 2 +
+			// buggy browsers will return more than the correct 0
+			document.getElementsByName( expando + 0 ).length;
+		assertGetIdNotName = !document.getElementById( expando );
+
+		// Cleanup
+		docElem.removeChild( div );
+
+		return pass;
+	});
+
+// If slice is not available, provide a backup
+try {
+	slice.call( docElem.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+	slice = function( i ) {
+		var elem,
+			results = [];
+		for ( ; (elem = this[i]); i++ ) {
+			results.push( elem );
+		}
+		return results;
+	};
+}
+
+function Sizzle( selector, context, results, seed ) {
+	results = results || [];
+	context = context || document;
+	var match, elem, xml, m,
+		nodeType = context.nodeType;
+
+	if ( !selector || typeof selector !== "string" ) {
+		return results;
+	}
+
+	if ( nodeType !== 1 && nodeType !== 9 ) {
+		return [];
+	}
+
+	xml = isXML( context );
+
+	if ( !xml && !seed ) {
+		if ( (match = rquickExpr.exec( selector )) ) {
+			// Speed-up: Sizzle("#ID")
+			if ( (m = match[1]) ) {
+				if ( nodeType === 9 ) {
+					elem = context.getElementById( m );
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE, Opera, and Webkit return items
+						// by name instead of ID
+						if ( elem.id === m ) {
+							results.push( elem );
+							return results;
+						}
+					} else {
+						return results;
+					}
+				} else {
+					// Context is not a document
+					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+						contains( context, elem ) && elem.id === m ) {
+						results.push( elem );
+						return results;
+					}
+				}
+
+			// Speed-up: Sizzle("TAG")
+			} else if ( match[2] ) {
+				push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+				return results;
+
+			// Speed-up: Sizzle(".CLASS")
+			} else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
+				push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+				return results;
+			}
+		}
+	}
+
+	// All others
+	return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
+}
+
+Sizzle.matches = function( expr, elements ) {
+	return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+	return Sizzle( expr, null, null, [ elem ] ).length > 0;
+};
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return name === "input" && elem.type === type;
+	};
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return (name === "input" || name === "button") && elem.type === type;
+	};
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+	return markFunction(function( argument ) {
+		argument = +argument;
+		return markFunction(function( seed, matches ) {
+			var j,
+				matchIndexes = fn( [], seed.length, argument ),
+				i = matchIndexes.length;
+
+			// Match elements found at the specified indexes
+			while ( i-- ) {
+				if ( seed[ (j = matchIndexes[i]) ] ) {
+					seed[j] = !(matches[j] = seed[j]);
+				}
+			}
+		});
+	});
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+	var node,
+		ret = "",
+		i = 0,
+		nodeType = elem.nodeType;
+
+	if ( nodeType ) {
+		if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+			// Use textContent for elements
+			// innerText usage removed for consistency of new lines (see #11153)
+			if ( typeof elem.textContent === "string" ) {
+				return elem.textContent;
+			} else {
+				// Traverse its children
+				for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+					ret += getText( elem );
+				}
+			}
+		} else if ( nodeType === 3 || nodeType === 4 ) {
+			return elem.nodeValue;
+		}
+		// Do not include comment or processing instruction nodes
+	} else {
+
+		// If no nodeType, this is expected to be an array
+		for ( ; (node = elem[i]); i++ ) {
+			// Do not traverse comment nodes
+			ret += getText( node );
+		}
+	}
+	return ret;
+};
+
+isXML = Sizzle.isXML = function( elem ) {
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833)
+	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Element contains another
+contains = Sizzle.contains = docElem.contains ?
+	function( a, b ) {
+		var adown = a.nodeType === 9 ? a.documentElement : a,
+			bup = b && b.parentNode;
+		return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
+	} :
+	docElem.compareDocumentPosition ?
+	function( a, b ) {
+		return b && !!( a.compareDocumentPosition( b ) & 16 );
+	} :
+	function( a, b ) {
+		while ( (b = b.parentNode) ) {
+			if ( b === a ) {
+				return true;
+			}
+		}
+		return false;
+	};
+
+Sizzle.attr = function( elem, name ) {
+	var val,
+		xml = isXML( elem );
+
+	if ( !xml ) {
+		name = name.toLowerCase();
+	}
+	if ( (val = Expr.attrHandle[ name ]) ) {
+		return val( elem );
+	}
+	if ( xml || assertAttributes ) {
+		return elem.getAttribute( name );
+	}
+	val = elem.getAttributeNode( name );
+	return val ?
+		typeof elem[ name ] === "boolean" ?
+			elem[ name ] ? name : null :
+			val.specified ? val.value : null :
+		null;
+};
+
+Expr = Sizzle.selectors = {
+
+	// Can be adjusted by the user
+	cacheLength: 50,
+
+	createPseudo: markFunction,
+
+	match: matchExpr,
+
+	// IE6/7 return a modified href
+	attrHandle: assertHrefNotNormalized ?
+		{} :
+		{
+			"href": function( elem ) {
+				return elem.getAttribute( "href", 2 );
+			},
+			"type": function( elem ) {
+				return elem.getAttribute("type");
+			}
+		},
+
+	find: {
+		"ID": assertGetIdNotName ?
+			function( id, context, xml ) {
+				if ( typeof context.getElementById !== strundefined && !xml ) {
+					var m = context.getElementById( id );
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					return m && m.parentNode ? [m] : [];
+				}
+			} :
+			function( id, context, xml ) {
+				if ( typeof context.getElementById !== strundefined && !xml ) {
+					var m = context.getElementById( id );
+
+					return m ?
+						m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+							[m] :
+							undefined :
+						[];
+				}
+			},
+
+		"TAG": assertTagNameNoComments ?
+			function( tag, context ) {
+				if ( typeof context.getElementsByTagName !== strundefined ) {
+					return context.getElementsByTagName( tag );
+				}
+			} :
+			function( tag, context ) {
+				var results = context.getElementsByTagName( tag );
+
+				// Filter out possible comments
+				if ( tag === "*" ) {
+					var elem,
+						tmp = [],
+						i = 0;
+
+					for ( ; (elem = results[i]); i++ ) {
+						if ( elem.nodeType === 1 ) {
+							tmp.push( elem );
+						}
+					}
+
+					return tmp;
+				}
+				return results;
+			},
+
+		"NAME": assertUsableName && function( tag, context ) {
+			if ( typeof context.getElementsByName !== strundefined ) {
+				return context.getElementsByName( name );
+			}
+		},
+
+		"CLASS": assertUsableClassName && function( className, context, xml ) {
+			if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
+				return context.getElementsByClassName( className );
+			}
+		}
+	},
+
+	relative: {
+		">": { dir: "parentNode", first: true },
+		" ": { dir: "parentNode" },
+		"+": { dir: "previousSibling", first: true },
+		"~": { dir: "previousSibling" }
+	},
+
+	preFilter: {
+		"ATTR": function( match ) {
+			match[1] = match[1].replace( rbackslash, "" );
+
+			// Move the given value to match[3] whether quoted or unquoted
+			match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
+
+			if ( match[2] === "~=" ) {
+				match[3] = " " + match[3] + " ";
+			}
+
+			return match.slice( 0, 4 );
+		},
+
+		"CHILD": function( match ) {
+			/* matches from matchExpr["CHILD"]
+				1 type (only|nth|...)
+				2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+				3 xn-component of xn+y argument ([+-]?\d*n|)
+				4 sign of xn-component
+				5 x of xn-component
+				6 sign of y-component
+				7 y of y-component
+			*/
+			match[1] = match[1].toLowerCase();
+
+			if ( match[1] === "nth" ) {
+				// nth-child requires argument
+				if ( !match[2] ) {
+					Sizzle.error( match[0] );
+				}
+
+				// numeric x and y parameters for Expr.filter.CHILD
+				// remember that false/true cast respectively to 0/1
+				match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
+				match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
+
+			// other types prohibit arguments
+			} else if ( match[2] ) {
+				Sizzle.error( match[0] );
+			}
+
+			return match;
+		},
+
+		"PSEUDO": function( match ) {
+			var unquoted, excess;
+			if ( matchExpr["CHILD"].test( match[0] ) ) {
+				return null;
+			}
+
+			if ( match[3] ) {
+				match[2] = match[3];
+			} else if ( (unquoted = match[4]) ) {
+				// Only check arguments that contain a pseudo
+				if ( rpseudo.test(unquoted) &&
+					// Get excess from tokenize (recursively)
+					(excess = tokenize( unquoted, true )) &&
+					// advance to the next closing parenthesis
+					(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+					// excess is a negative index
+					unquoted = unquoted.slice( 0, excess );
+					match[0] = match[0].slice( 0, excess );
+				}
+				match[2] = unquoted;
+			}
+
+			// Return only captures needed by the pseudo filter method (type and argument)
+			return match.slice( 0, 3 );
+		}
+	},
+
+	filter: {
+		"ID": assertGetIdNotName ?
+			function( id ) {
+				id = id.replace( rbackslash, "" );
+				return function( elem ) {
+					return elem.getAttribute("id") === id;
+				};
+			} :
+			function( id ) {
+				id = id.replace( rbackslash, "" );
+				return function( elem ) {
+					var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+					return node && node.value === id;
+				};
+			},
+
+		"TAG": function( nodeName ) {
+			if ( nodeName === "*" ) {
+				return function() { return true; };
+			}
+			nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
+
+			return function( elem ) {
+				return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+			};
+		},
+
+		"CLASS": function( className ) {
+			var pattern = classCache[ expando ][ className + " " ];
+
+			return pattern ||
+				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+				classCache( className, function( elem ) {
+					return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+				});
+		},
+
+		"ATTR": function( name, operator, check ) {
+			return function( elem, context ) {
+				var result = Sizzle.attr( elem, name );
+
+				if ( result == null ) {
+					return operator === "!=";
+				}
+				if ( !operator ) {
+					return true;
+				}
+
+				result += "";
+
+				return operator === "=" ? result === check :
+					operator === "!=" ? result !== check :
+					operator === "^=" ? check && result.indexOf( check ) === 0 :
+					operator === "*=" ? check && result.indexOf( check ) > -1 :
+					operator === "$=" ? check && result.substr( result.length - check.length ) === check :
+					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+					operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
+					false;
+			};
+		},
+
+		"CHILD": function( type, argument, first, last ) {
+
+			if ( type === "nth" ) {
+				return function( elem ) {
+					var node, diff,
+						parent = elem.parentNode;
+
+					if ( first === 1 && last === 0 ) {
+						return true;
+					}
+
+					if ( parent ) {
+						diff = 0;
+						for ( node = parent.firstChild; node; node = node.nextSibling ) {
+							if ( node.nodeType === 1 ) {
+								diff++;
+								if ( elem === node ) {
+									break;
+								}
+							}
+						}
+					}
+
+					// Incorporate the offset (or cast to NaN), then check against cycle size
+					diff -= last;
+					return diff === first || ( diff % first === 0 && diff / first >= 0 );
+				};
+			}
+
+			return function( elem ) {
+				var node = elem;
+
+				switch ( type ) {
+					case "only":
+					case "first":
+						while ( (node = node.previousSibling) ) {
+							if ( node.nodeType === 1 ) {
+								return false;
+							}
+						}
+
+						if ( type === "first" ) {
+							return true;
+						}
+
+						node = elem;
+
+						/* falls through */
+					case "last":
+						while ( (node = node.nextSibling) ) {
+							if ( node.nodeType === 1 ) {
+								return false;
+							}
+						}
+
+						return true;
+				}
+			};
+		},
+
+		"PSEUDO": function( pseudo, argument ) {
+			// pseudo-class names are case-insensitive
+			// http://www.w3.org/TR/selectors/#pseudo-classes
+			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+			// Remember that setFilters inherits from pseudos
+			var args,
+				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+					Sizzle.error( "unsupported pseudo: " + pseudo );
+
+			// The user may use createPseudo to indicate that
+			// arguments are needed to create the filter function
+			// just as Sizzle does
+			if ( fn[ expando ] ) {
+				return fn( argument );
+			}
+
+			// But maintain support for old signatures
+			if ( fn.length > 1 ) {
+				args = [ pseudo, pseudo, "", argument ];
+				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+					markFunction(function( seed, matches ) {
+						var idx,
+							matched = fn( seed, argument ),
+							i = matched.length;
+						while ( i-- ) {
+							idx = indexOf.call( seed, matched[i] );
+							seed[ idx ] = !( matches[ idx ] = matched[i] );
+						}
+					}) :
+					function( elem ) {
+						return fn( elem, 0, args );
+					};
+			}
+
+			return fn;
+		}
+	},
+
+	pseudos: {
+		"not": markFunction(function( selector ) {
+			// Trim the selector passed to compile
+			// to avoid treating leading and trailing
+			// spaces as combinators
+			var input = [],
+				results = [],
+				matcher = compile( selector.replace( rtrim, "$1" ) );
+
+			return matcher[ expando ] ?
+				markFunction(function( seed, matches, context, xml ) {
+					var elem,
+						unmatched = matcher( seed, null, xml, [] ),
+						i = seed.length;
+
+					// Match elements unmatched by `matcher`
+					while ( i-- ) {
+						if ( (elem = unmatched[i]) ) {
+							seed[i] = !(matches[i] = elem);
+						}
+					}
+				}) :
+				function( elem, context, xml ) {
+					input[0] = elem;
+					matcher( input, null, xml, results );
+					return !results.pop();
+				};
+		}),
+
+		"has": markFunction(function( selector ) {
+			return function( elem ) {
+				return Sizzle( selector, elem ).length > 0;
+			};
+		}),
+
+		"contains": markFunction(function( text ) {
+			return function( elem ) {
+				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+			};
+		}),
+
+		"enabled": function( elem ) {
+			return elem.disabled === false;
+		},
+
+		"disabled": function( elem ) {
+			return elem.disabled === true;
+		},
+
+		"checked": function( elem ) {
+			// In CSS3, :checked should return both checked and selected elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			var nodeName = elem.nodeName.toLowerCase();
+			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+		},
+
+		"selected": function( elem ) {
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
+
+			return elem.selected === true;
+		},
+
+		"parent": function( elem ) {
+			return !Expr.pseudos["empty"]( elem );
+		},
+
+		"empty": function( elem ) {
+			// http://www.w3.org/TR/selectors/#empty-pseudo
+			// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+			//   not comment, processing instructions, or others
+			// Thanks to Diego Perini for the nodeName shortcut
+			//   Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+			var nodeType;
+			elem = elem.firstChild;
+			while ( elem ) {
+				if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
+					return false;
+				}
+				elem = elem.nextSibling;
+			}
+			return true;
+		},
+
+		"header": function( elem ) {
+			return rheader.test( elem.nodeName );
+		},
+
+		"text": function( elem ) {
+			var type, attr;
+			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+			// use getAttribute instead to test this case
+			return elem.nodeName.toLowerCase() === "input" &&
+				(type = elem.type) === "text" &&
+				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
+		},
+
+		// Input types
+		"radio": createInputPseudo("radio"),
+		"checkbox": createInputPseudo("checkbox"),
+		"file": createInputPseudo("file"),
+		"password": createInputPseudo("password"),
+		"image": createInputPseudo("image"),
+
+		"submit": createButtonPseudo("submit"),
+		"reset": createButtonPseudo("reset"),
+
+		"button": function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return name === "input" && elem.type === "button" || name === "button";
+		},
+
+		"input": function( elem ) {
+			return rinputs.test( elem.nodeName );
+		},
+
+		"focus": function( elem ) {
+			var doc = elem.ownerDocument;
+			return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+		},
+
+		"active": function( elem ) {
+			return elem === elem.ownerDocument.activeElement;
+		},
+
+		// Positional types
+		"first": createPositionalPseudo(function() {
+			return [ 0 ];
+		}),
+
+		"last": createPositionalPseudo(function( matchIndexes, length ) {
+			return [ length - 1 ];
+		}),
+
+		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			return [ argument < 0 ? argument + length : argument ];
+		}),
+
+		"even": createPositionalPseudo(function( matchIndexes, length ) {
+			for ( var i = 0; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"odd": createPositionalPseudo(function( matchIndexes, length ) {
+			for ( var i = 1; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		})
+	}
+};
+
+function siblingCheck( a, b, ret ) {
+	if ( a === b ) {
+		return ret;
+	}
+
+	var cur = a.nextSibling;
+
+	while ( cur ) {
+		if ( cur === b ) {
+			return -1;
+		}
+
+		cur = cur.nextSibling;
+	}
+
+	return 1;
+}
+
+sortOrder = docElem.compareDocumentPosition ?
+	function( a, b ) {
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
+			a.compareDocumentPosition :
+			a.compareDocumentPosition(b) & 4
+		) ? -1 : 1;
+	} :
+	function( a, b ) {
+		// The nodes are identical, we can exit early
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+
+		// Fallback to using sourceIndex (in IE) if it's available on both nodes
+		} else if ( a.sourceIndex && b.sourceIndex ) {
+			return a.sourceIndex - b.sourceIndex;
+		}
+
+		var al, bl,
+			ap = [],
+			bp = [],
+			aup = a.parentNode,
+			bup = b.parentNode,
+			cur = aup;
+
+		// If the nodes are siblings (or identical) we can do a quick check
+		if ( aup === bup ) {
+			return siblingCheck( a, b );
+
+		// If no parents were found then the nodes are disconnected
+		} else if ( !aup ) {
+			return -1;
+
+		} else if ( !bup ) {
+			return 1;
+		}
+
+		// Otherwise they're somewhere else in the tree so we need
+		// to build up a full list of the parentNodes for comparison
+		while ( cur ) {
+			ap.unshift( cur );
+			cur = cur.parentNode;
+		}
+
+		cur = bup;
+
+		while ( cur ) {
+			bp.unshift( cur );
+			cur = cur.parentNode;
+		}
+
+		al = ap.length;
+		bl = bp.length;
+
+		// Start walking down the tree looking for a discrepancy
+		for ( var i = 0; i < al && i < bl; i++ ) {
+			if ( ap[i] !== bp[i] ) {
+				return siblingCheck( ap[i], bp[i] );
+			}
+		}
+
+		// We ended someplace up the tree so do a sibling check
+		return i === al ?
+			siblingCheck( a, bp[i], -1 ) :
+			siblingCheck( ap[i], b, 1 );
+	};
+
+// Always assume the presence of duplicates if sort doesn't
+// pass them to our comparison function (as in Google Chrome).
+[0, 0].sort( sortOrder );
+baseHasDuplicate = !hasDuplicate;
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+	var elem,
+		duplicates = [],
+		i = 1,
+		j = 0;
+
+	hasDuplicate = baseHasDuplicate;
+	results.sort( sortOrder );
+
+	if ( hasDuplicate ) {
+		for ( ; (elem = results[i]); i++ ) {
+			if ( elem === results[ i - 1 ] ) {
+				j = duplicates.push( i );
+			}
+		}
+		while ( j-- ) {
+			results.splice( duplicates[ j ], 1 );
+		}
+	}
+
+	return results;
+};
+
+Sizzle.error = function( msg ) {
+	throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+function tokenize( selector, parseOnly ) {
+	var matched, match, tokens, type,
+		soFar, groups, preFilters,
+		cached = tokenCache[ expando ][ selector + " " ];
+
+	if ( cached ) {
+		return parseOnly ? 0 : cached.slice( 0 );
+	}
+
+	soFar = selector;
+	groups = [];
+	preFilters = Expr.preFilter;
+
+	while ( soFar ) {
+
+		// Comma and first run
+		if ( !matched || (match = rcomma.exec( soFar )) ) {
+			if ( match ) {
+				// Don't consume trailing commas as valid
+				soFar = soFar.slice( match[0].length ) || soFar;
+			}
+			groups.push( tokens = [] );
+		}
+
+		matched = false;
+
+		// Combinators
+		if ( (match = rcombinators.exec( soFar )) ) {
+			tokens.push( matched = new Token( match.shift() ) );
+			soFar = soFar.slice( matched.length );
+
+			// Cast descendant combinators to space
+			matched.type = match[0].replace( rtrim, " " );
+		}
+
+		// Filters
+		for ( type in Expr.filter ) {
+			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+				(match = preFilters[ type ]( match ))) ) {
+
+				tokens.push( matched = new Token( match.shift() ) );
+				soFar = soFar.slice( matched.length );
+				matched.type = type;
+				matched.matches = match;
+			}
+		}
+
+		if ( !matched ) {
+			break;
+		}
+	}
+
+	// Return the length of the invalid excess
+	// if we're just parsing
+	// Otherwise, throw an error or return tokens
+	return parseOnly ?
+		soFar.length :
+		soFar ?
+			Sizzle.error( selector ) :
+			// Cache the tokens
+			tokenCache( selector, groups ).slice( 0 );
+}
+
+function addCombinator( matcher, combinator, base ) {
+	var dir = combinator.dir,
+		checkNonElements = base && combinator.dir === "parentNode",
+		doneName = done++;
+
+	return combinator.first ?
+		// Check against closest ancestor/preceding element
+		function( elem, context, xml ) {
+			while ( (elem = elem[ dir ]) ) {
+				if ( checkNonElements || elem.nodeType === 1  ) {
+					return matcher( elem, context, xml );
+				}
+			}
+		} :
+
+		// Check against all ancestor/preceding elements
+		function( elem, context, xml ) {
+			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+			if ( !xml ) {
+				var cache,
+					dirkey = dirruns + " " + doneName + " ",
+					cachedkey = dirkey + cachedruns;
+				while ( (elem = elem[ dir ]) ) {
+					if ( checkNonElements || elem.nodeType === 1 ) {
+						if ( (cache = elem[ expando ]) === cachedkey ) {
+							return elem.sizset;
+						} else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
+							if ( elem.sizset ) {
+								return elem;
+							}
+						} else {
+							elem[ expando ] = cachedkey;
+							if ( matcher( elem, context, xml ) ) {
+								elem.sizset = true;
+								return elem;
+							}
+							elem.sizset = false;
+						}
+					}
+				}
+			} else {
+				while ( (elem = elem[ dir ]) ) {
+					if ( checkNonElements || elem.nodeType === 1 ) {
+						if ( matcher( elem, context, xml ) ) {
+							return elem;
+						}
+					}
+				}
+			}
+		};
+}
+
+function elementMatcher( matchers ) {
+	return matchers.length > 1 ?
+		function( elem, context, xml ) {
+			var i = matchers.length;
+			while ( i-- ) {
+				if ( !matchers[i]( elem, context, xml ) ) {
+					return false;
+				}
+			}
+			return true;
+		} :
+		matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+	var elem,
+		newUnmatched = [],
+		i = 0,
+		len = unmatched.length,
+		mapped = map != null;
+
+	for ( ; i < len; i++ ) {
+		if ( (elem = unmatched[i]) ) {
+			if ( !filter || filter( elem, context, xml ) ) {
+				newUnmatched.push( elem );
+				if ( mapped ) {
+					map.push( i );
+				}
+			}
+		}
+	}
+
+	return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+	if ( postFilter && !postFilter[ expando ] ) {
+		postFilter = setMatcher( postFilter );
+	}
+	if ( postFinder && !postFinder[ expando ] ) {
+		postFinder = setMatcher( postFinder, postSelector );
+	}
+	return markFunction(function( seed, results, context, xml ) {
+		var temp, i, elem,
+			preMap = [],
+			postMap = [],
+			preexisting = results.length,
+
+			// Get initial elements from seed or context
+			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+			// Prefilter to get matcher input, preserving a map for seed-results synchronization
+			matcherIn = preFilter && ( seed || !selector ) ?
+				condense( elems, preMap, preFilter, context, xml ) :
+				elems,
+
+			matcherOut = matcher ?
+				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+					// ...intermediate processing is necessary
+					[] :
+
+					// ...otherwise use results directly
+					results :
+				matcherIn;
+
+		// Find primary matches
+		if ( matcher ) {
+			matcher( matcherIn, matcherOut, context, xml );
+		}
+
+		// Apply postFilter
+		if ( postFilter ) {
+			temp = condense( matcherOut, postMap );
+			postFilter( temp, [], context, xml );
+
+			// Un-match failing elements by moving them back to matcherIn
+			i = temp.length;
+			while ( i-- ) {
+				if ( (elem = temp[i]) ) {
+					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+				}
+			}
+		}
+
+		if ( seed ) {
+			if ( postFinder || preFilter ) {
+				if ( postFinder ) {
+					// Get the final matcherOut by condensing this intermediate into postFinder contexts
+					temp = [];
+					i = matcherOut.length;
+					while ( i-- ) {
+						if ( (elem = matcherOut[i]) ) {
+							// Restore matcherIn since elem is not yet a final match
+							temp.push( (matcherIn[i] = elem) );
+						}
+					}
+					postFinder( null, (matcherOut = []), temp, xml );
+				}
+
+				// Move matched elements from seed to results to keep them synchronized
+				i = matcherOut.length;
+				while ( i-- ) {
+					if ( (elem = matcherOut[i]) &&
+						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+						seed[temp] = !(results[temp] = elem);
+					}
+				}
+			}
+
+		// Add elements to results, through postFinder if defined
+		} else {
+			matcherOut = condense(
+				matcherOut === results ?
+					matcherOut.splice( preexisting, matcherOut.length ) :
+					matcherOut
+			);
+			if ( postFinder ) {
+				postFinder( null, results, matcherOut, xml );
+			} else {
+				push.apply( results, matcherOut );
+			}
+		}
+	});
+}
+
+function matcherFromTokens( tokens ) {
+	var checkContext, matcher, j,
+		len = tokens.length,
+		leadingRelative = Expr.relative[ tokens[0].type ],
+		implicitRelative = leadingRelative || Expr.relative[" "],
+		i = leadingRelative ? 1 : 0,
+
+		// The foundational matcher ensures that elements are reachable from top-level context(s)
+		matchContext = addCombinator( function( elem ) {
+			return elem === checkContext;
+		}, implicitRelative, true ),
+		matchAnyContext = addCombinator( function( elem ) {
+			return indexOf.call( checkContext, elem ) > -1;
+		}, implicitRelative, true ),
+		matchers = [ function( elem, context, xml ) {
+			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+				(checkContext = context).nodeType ?
+					matchContext( elem, context, xml ) :
+					matchAnyContext( elem, context, xml ) );
+		} ];
+
+	for ( ; i < len; i++ ) {
+		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+			matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+		} else {
+			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+			// Return special upon seeing a positional matcher
+			if ( matcher[ expando ] ) {
+				// Find the next relative operator (if any) for proper handling
+				j = ++i;
+				for ( ; j < len; j++ ) {
+					if ( Expr.relative[ tokens[j].type ] ) {
+						break;
+					}
+				}
+				return setMatcher(
+					i > 1 && elementMatcher( matchers ),
+					i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
+					matcher,
+					i < j && matcherFromTokens( tokens.slice( i, j ) ),
+					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+					j < len && tokens.join("")
+				);
+			}
+			matchers.push( matcher );
+		}
+	}
+
+	return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+	var bySet = setMatchers.length > 0,
+		byElement = elementMatchers.length > 0,
+		superMatcher = function( seed, context, xml, results, expandContext ) {
+			var elem, j, matcher,
+				setMatched = [],
+				matchedCount = 0,
+				i = "0",
+				unmatched = seed && [],
+				outermost = expandContext != null,
+				contextBackup = outermostContext,
+				// We must always have either seed elements or context
+				elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+				// Nested matchers should use non-integer dirruns
+				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+
+			if ( outermost ) {
+				outermostContext = context !== document && context;
+				cachedruns = superMatcher.el;
+			}
+
+			// Add elements passing elementMatchers directly to results
+			for ( ; (elem = elems[i]) != null; i++ ) {
+				if ( byElement && elem ) {
+					for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
+						if ( matcher( elem, context, xml ) ) {
+							results.push( elem );
+							break;
+						}
+					}
+					if ( outermost ) {
+						dirruns = dirrunsUnique;
+						cachedruns = ++superMatcher.el;
+					}
+				}
+
+				// Track unmatched elements for set filters
+				if ( bySet ) {
+					// They will have gone through all possible matchers
+					if ( (elem = !matcher && elem) ) {
+						matchedCount--;
+					}
+
+					// Lengthen the array for every element, matched or not
+					if ( seed ) {
+						unmatched.push( elem );
+					}
+				}
+			}
+
+			// Apply set filters to unmatched elements
+			matchedCount += i;
+			if ( bySet && i !== matchedCount ) {
+				for ( j = 0; (matcher = setMatchers[j]); j++ ) {
+					matcher( unmatched, setMatched, context, xml );
+				}
+
+				if ( seed ) {
+					// Reintegrate element matches to eliminate the need for sorting
+					if ( matchedCount > 0 ) {
+						while ( i-- ) {
+							if ( !(unmatched[i] || setMatched[i]) ) {
+								setMatched[i] = pop.call( results );
+							}
+						}
+					}
+
+					// Discard index placeholder values to get only actual matches
+					setMatched = condense( setMatched );
+				}
+
+				// Add matches to results
+				push.apply( results, setMatched );
+
+				// Seedless set matches succeeding multiple successful matchers stipulate sorting
+				if ( outermost && !seed && setMatched.length > 0 &&
+					( matchedCount + setMatchers.length ) > 1 ) {
+
+					Sizzle.uniqueSort( results );
+				}
+			}
+
+			// Override manipulation of globals by nested matchers
+			if ( outermost ) {
+				dirruns = dirrunsUnique;
+				outermostContext = contextBackup;
+			}
+
+			return unmatched;
+		};
+
+	superMatcher.el = 0;
+	return bySet ?
+		markFunction( superMatcher ) :
+		superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+	var i,
+		setMatchers = [],
+		elementMatchers = [],
+		cached = compilerCache[ expando ][ selector + " " ];
+
+	if ( !cached ) {
+		// Generate a function of recursive functions that can be used to check each element
+		if ( !group ) {
+			group = tokenize( selector );
+		}
+		i = group.length;
+		while ( i-- ) {
+			cached = matcherFromTokens( group[i] );
+			if ( cached[ expando ] ) {
+				setMatchers.push( cached );
+			} else {
+				elementMatchers.push( cached );
+			}
+		}
+
+		// Cache the compiled function
+		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+	}
+	return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+	var i = 0,
+		len = contexts.length;
+	for ( ; i < len; i++ ) {
+		Sizzle( selector, contexts[i], results );
+	}
+	return results;
+}
+
+function select( selector, context, results, seed, xml ) {
+	var i, tokens, token, type, find,
+		match = tokenize( selector ),
+		j = match.length;
+
+	if ( !seed ) {
+		// Try to minimize operations if there is only one group
+		if ( match.length === 1 ) {
+
+			// Take a shortcut and set the context if the root selector is an ID
+			tokens = match[0] = match[0].slice( 0 );
+			if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+					context.nodeType === 9 && !xml &&
+					Expr.relative[ tokens[1].type ] ) {
+
+				context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
+				if ( !context ) {
+					return results;
+				}
+
+				selector = selector.slice( tokens.shift().length );
+			}
+
+			// Fetch a seed set for right-to-left matching
+			for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
+				token = tokens[i];
+
+				// Abort if we hit a combinator
+				if ( Expr.relative[ (type = token.type) ] ) {
+					break;
+				}
+				if ( (find = Expr.find[ type ]) ) {
+					// Search, expanding context for leading sibling combinators
+					if ( (seed = find(
+						token.matches[0].replace( rbackslash, "" ),
+						rsibling.test( tokens[0].type ) && context.parentNode || context,
+						xml
+					)) ) {
+
+						// If seed is empty or no tokens remain, we can return early
+						tokens.splice( i, 1 );
+						selector = seed.length && tokens.join("");
+						if ( !selector ) {
+							push.apply( results, slice.call( seed, 0 ) );
+							return results;
+						}
+
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	// Compile and execute a filtering function
+	// Provide `match` to avoid retokenization if we modified the selector above
+	compile( selector, match )(
+		seed,
+		context,
+		xml,
+		results,
+		rsibling.test( selector )
+	);
+	return results;
+}
+
+if ( document.querySelectorAll ) {
+	(function() {
+		var disconnectedMatch,
+			oldSelect = select,
+			rescape = /'|\\/g,
+			rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+			// qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA
+			// A support test would require too much code (would include document ready)
+			rbuggyQSA = [ ":focus" ],
+
+			// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+			// A support test would require too much code (would include document ready)
+			// just skip matchesSelector for :active
+			rbuggyMatches = [ ":active" ],
+			matches = docElem.matchesSelector ||
+				docElem.mozMatchesSelector ||
+				docElem.webkitMatchesSelector ||
+				docElem.oMatchesSelector ||
+				docElem.msMatchesSelector;
+
+		// Build QSA regex
+		// Regex strategy adopted from Diego Perini
+		assert(function( div ) {
+			// Select is set to empty string on purpose
+			// This is to test IE's treatment of not explictly
+			// setting a boolean content attribute,
+			// since its presence should be enough
+			// http://bugs.jquery.com/ticket/12359
+			div.innerHTML = "<select><option selected=''></option></select>";
+
+			// IE8 - Some boolean attributes are not treated correctly
+			if ( !div.querySelectorAll("[selected]").length ) {
+				rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+			}
+
+			// Webkit/Opera - :checked should return selected option elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			// IE8 throws error here (do not put tests after this one)
+			if ( !div.querySelectorAll(":checked").length ) {
+				rbuggyQSA.push(":checked");
+			}
+		});
+
+		assert(function( div ) {
+
+			// Opera 10-12/IE9 - ^= $= *= and empty values
+			// Should not select anything
+			div.innerHTML = "<p test=''></p>";
+			if ( div.querySelectorAll("[test^='']").length ) {
+				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+			}
+
+			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+			// IE8 throws error here (do not put tests after this one)
+			div.innerHTML = "<input type='hidden'/>";
+			if ( !div.querySelectorAll(":enabled").length ) {
+				rbuggyQSA.push(":enabled", ":disabled");
+			}
+		});
+
+		// rbuggyQSA always contains :focus, so no need for a length check
+		rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
+
+		select = function( selector, context, results, seed, xml ) {
+			// Only use querySelectorAll when not filtering,
+			// when this is not xml,
+			// and when no QSA bugs apply
+			if ( !seed && !xml && !rbuggyQSA.test( selector ) ) {
+				var groups, i,
+					old = true,
+					nid = expando,
+					newContext = context,
+					newSelector = context.nodeType === 9 && selector;
+
+				// qSA works strangely on Element-rooted queries
+				// We can work around this by specifying an extra ID on the root
+				// and working up from there (Thanks to Andrew Dupont for the technique)
+				// IE 8 doesn't work on object elements
+				if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+					groups = tokenize( selector );
+
+					if ( (old = context.getAttribute("id")) ) {
+						nid = old.replace( rescape, "\\$&" );
+					} else {
+						context.setAttribute( "id", nid );
+					}
+					nid = "[id='" + nid + "'] ";
+
+					i = groups.length;
+					while ( i-- ) {
+						groups[i] = nid + groups[i].join("");
+					}
+					newContext = rsibling.test( selector ) && context.parentNode || context;
+					newSelector = groups.join(",");
+				}
+
+				if ( newSelector ) {
+					try {
+						push.apply( results, slice.call( newContext.querySelectorAll(
+							newSelector
+						), 0 ) );
+						return results;
+					} catch(qsaError) {
+					} finally {
+						if ( !old ) {
+							context.removeAttribute("id");
+						}
+					}
+				}
+			}
+
+			return oldSelect( selector, context, results, seed, xml );
+		};
+
+		if ( matches ) {
+			assert(function( div ) {
+				// Check to see if it's possible to do matchesSelector
+				// on a disconnected node (IE 9)
+				disconnectedMatch = matches.call( div, "div" );
+
+				// This should fail with an exception
+				// Gecko does not error, returns false instead
+				try {
+					matches.call( div, "[test!='']:sizzle" );
+					rbuggyMatches.push( "!=", pseudos );
+				} catch ( e ) {}
+			});
+
+			// rbuggyMatches always contains :active and :focus, so no need for a length check
+			rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
+
+			Sizzle.matchesSelector = function( elem, expr ) {
+				// Make sure that attribute selectors are quoted
+				expr = expr.replace( rattributeQuotes, "='$1']" );
+
+				// rbuggyMatches always contains :active, so no need for an existence check
+				if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) {
+					try {
+						var ret = matches.call( elem, expr );
+
+						// IE 9's matchesSelector returns false on disconnected nodes
+						if ( ret || disconnectedMatch ||
+								// As well, disconnected nodes are said to be in a document
+								// fragment in IE 9
+								elem.document && elem.document.nodeType !== 11 ) {
+							return ret;
+						}
+					} catch(e) {}
+				}
+
+				return Sizzle( expr, null, null, [ elem ] ).length > 0;
+			};
+		}
+	})();
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Back-compat
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+var runtil = /Until$/,
+	rparentsprev = /^(?:parents|prev(?:Until|All))/,
+	isSimple = /^.[^:#\[\.,]*$/,
+	rneedsContext = jQuery.expr.match.needsContext,
+	// methods guaranteed to produce a unique set when starting from a unique set
+	guaranteedUnique = {
+		children: true,
+		contents: true,
+		next: true,
+		prev: true
+	};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var i, l, length, n, r, ret,
+			self = this;
+
+		if ( typeof selector !== "string" ) {
+			return jQuery( selector ).filter(function() {
+				for ( i = 0, l = self.length; i < l; i++ ) {
+					if ( jQuery.contains( self[ i ], this ) ) {
+						return true;
+					}
+				}
+			});
+		}
+
+		ret = this.pushStack( "", "find", selector );
+
+		for ( i = 0, l = this.length; i < l; i++ ) {
+			length = ret.length;
+			jQuery.find( selector, this[i], ret );
+
+			if ( i > 0 ) {
+				// Make sure that the results are unique
+				for ( n = length; n < ret.length; n++ ) {
+					for ( r = 0; r < length; r++ ) {
+						if ( ret[r] === ret[n] ) {
+							ret.splice(n--, 1);
+							break;
+						}
+					}
+				}
+			}
+		}
+
+		return ret;
+	},
+
+	has: function( target ) {
+		var i,
+			targets = jQuery( target, this ),
+			len = targets.length;
+
+		return this.filter(function() {
+			for ( i = 0; i < len; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector, false), "not", selector);
+	},
+
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector, true), "filter", selector );
+	},
+
+	is: function( selector ) {
+		return !!selector && (
+			typeof selector === "string" ?
+				// If this is a positional/relative selector, check membership in the returned set
+				// so $("p:first").is("p:last") won't return true for a doc with two "p".
+				rneedsContext.test( selector ) ?
+					jQuery( selector, this.context ).index( this[0] ) >= 0 :
+					jQuery.filter( selector, this ).length > 0 :
+				this.filter( selector ).length > 0 );
+	},
+
+	closest: function( selectors, context ) {
+		var cur,
+			i = 0,
+			l = this.length,
+			ret = [],
+			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+				jQuery( selectors, context || this.context ) :
+				0;
+
+		for ( ; i < l; i++ ) {
+			cur = this[i];
+
+			while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
+				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+					ret.push( cur );
+					break;
+				}
+				cur = cur.parentNode;
+			}
+		}
+
+		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+		return this.pushStack( ret, "closest", selectors );
+	},
+
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+
+		// No argument, return index in parent
+		if ( !elem ) {
+			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+		}
+
+		// index in selector
+		if ( typeof elem === "string" ) {
+			return jQuery.inArray( this[0], jQuery( elem ) );
+		}
+
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[0] : elem, this );
+	},
+
+	add: function( selector, context ) {
+		var set = typeof selector === "string" ?
+				jQuery( selector, context ) :
+				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+			all = jQuery.merge( this.get(), set );
+
+		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+			all :
+			jQuery.unique( all ) );
+	},
+
+	addBack: function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter(selector)
+		);
+	}
+});
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+	return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+function sibling( cur, dir ) {
+	do {
+		cur = cur[ dir ];
+	} while ( cur && cur.nodeType !== 1 );
+
+	return cur;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return sibling( elem, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return sibling( elem, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return jQuery.nodeName( elem, "iframe" ) ?
+			elem.contentDocument || elem.contentWindow.document :
+			jQuery.merge( [], elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var ret = jQuery.map( this, fn, until );
+
+		if ( !runtil.test( name ) ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			ret = jQuery.filter( selector, ret );
+		}
+
+		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+		if ( this.length > 1 && rparentsprev.test( name ) ) {
+			ret = ret.reverse();
+		}
+
+		return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
+	};
+});
+
+jQuery.extend({
+	filter: function( expr, elems, not ) {
+		if ( not ) {
+			expr = ":not(" + expr + ")";
+		}
+
+		return elems.length === 1 ?
+			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+			jQuery.find.matches(expr, elems);
+	},
+
+	dir: function( elem, dir, until ) {
+		var matched = [],
+			cur = elem[ dir ];
+
+		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+			if ( cur.nodeType === 1 ) {
+				matched.push( cur );
+			}
+			cur = cur[dir];
+		}
+		return matched;
+	},
+
+	sibling: function( n, elem ) {
+		var r = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				r.push( n );
+			}
+		}
+
+		return r;
+	}
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+	// Can't pass null or undefined to indexOf in Firefox 4
+	// Set to 0 to skip string check
+	qualifier = qualifier || 0;
+
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			var retVal = !!qualifier.call( elem, i, elem );
+			return retVal === keep;
+		});
+
+	} else if ( qualifier.nodeType ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			return ( elem === qualifier ) === keep;
+		});
+
+	} else if ( typeof qualifier === "string" ) {
+		var filtered = jQuery.grep(elements, function( elem ) {
+			return elem.nodeType === 1;
+		});
+
+		if ( isSimple.test( qualifier ) ) {
+			return jQuery.filter(qualifier, filtered, !keep);
+		} else {
+			qualifier = jQuery.filter( qualifier, filtered );
+		}
+	}
+
+	return jQuery.grep(elements, function( elem, i ) {
+		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+	});
+}
+function createSafeFragment( document ) {
+	var list = nodeNames.split( "|" ),
+	safeFrag = document.createDocumentFragment();
+
+	if ( safeFrag.createElement ) {
+		while ( list.length ) {
+			safeFrag.createElement(
+				list.pop()
+			);
+		}
+	}
+	return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+	rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+	rleadingWhitespace = /^\s+/,
+	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+	rtagName = /<([\w:]+)/,
+	rtbody = /<tbody/i,
+	rhtml = /<|&#?\w+;/,
+	rnoInnerhtml = /<(?:script|style|link)/i,
+	rnocache = /<(?:script|object|embed|option|style)/i,
+	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+	rcheckableType = /^(?:checkbox|radio)$/,
+	// checked="checked" or checked
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+	rscriptType = /\/(java|ecma)script/i,
+	rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,
+	wrapMap = {
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+		legend: [ 1, "<fieldset>", "</fieldset>" ],
+		thead: [ 1, "<table>", "</table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+		area: [ 1, "<map>", "</map>" ],
+		_default: [ 0, "", "" ]
+	},
+	safeFragment = createSafeFragment( document ),
+	fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+// unless wrapped in a div with non-breaking characters in front of it.
+if ( !jQuery.support.htmlSerialize ) {
+	wrapMap._default = [ 1, "X<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+	text: function( value ) {
+		return jQuery.access( this, function( value ) {
+			return value === undefined ?
+				jQuery.text( this ) :
+				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+		}, null, value, arguments.length );
+	},
+
+	wrapAll: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+			if ( this[0].parentNode ) {
+				wrap.insertBefore( this[0] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+					elem = elem.firstChild;
+				}
+
+				return elem;
+			}).append( this );
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ),
+				contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		var isFunction = jQuery.isFunction( html );
+
+		return this.each(function(i) {
+			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	},
+
+	append: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 ) {
+				this.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 ) {
+				this.insertBefore( elem, this.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		if ( !isDisconnected( this[0] ) ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this );
+			});
+		}
+
+		if ( arguments.length ) {
+			var set = jQuery.clean( arguments );
+			return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
+		}
+	},
+
+	after: function() {
+		if ( !isDisconnected( this[0] ) ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			});
+		}
+
+		if ( arguments.length ) {
+			var set = jQuery.clean( arguments );
+			return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
+		}
+	},
+
+	// keepData is for internal use only--do not document
+	remove: function( selector, keepData ) {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+				if ( !keepData && elem.nodeType === 1 ) {
+					jQuery.cleanData( elem.getElementsByTagName("*") );
+					jQuery.cleanData( [ elem ] );
+				}
+
+				if ( elem.parentNode ) {
+					elem.parentNode.removeChild( elem );
+				}
+			}
+		}
+
+		return this;
+	},
+
+	empty: function() {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			// Remove element nodes and prevent memory leaks
+			if ( elem.nodeType === 1 ) {
+				jQuery.cleanData( elem.getElementsByTagName("*") );
+			}
+
+			// Remove any remaining nodes
+			while ( elem.firstChild ) {
+				elem.removeChild( elem.firstChild );
+			}
+		}
+
+		return this;
+	},
+
+	clone: function( dataAndEvents, deepDataAndEvents ) {
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+		return this.map( function () {
+			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+		});
+	},
+
+	html: function( value ) {
+		return jQuery.access( this, function( value ) {
+			var elem = this[0] || {},
+				i = 0,
+				l = this.length;
+
+			if ( value === undefined ) {
+				return elem.nodeType === 1 ?
+					elem.innerHTML.replace( rinlinejQuery, "" ) :
+					undefined;
+			}
+
+			// See if we can take a shortcut and just use innerHTML
+			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+				( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
+				( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+				!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+				value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+				try {
+					for (; i < l; i++ ) {
+						// Remove element nodes and prevent memory leaks
+						elem = this[i] || {};
+						if ( elem.nodeType === 1 ) {
+							jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+							elem.innerHTML = value;
+						}
+					}
+
+					elem = 0;
+
+				// If using innerHTML throws an exception, use the fallback method
+				} catch(e) {}
+			}
+
+			if ( elem ) {
+				this.empty().append( value );
+			}
+		}, null, value, arguments.length );
+	},
+
+	replaceWith: function( value ) {
+		if ( !isDisconnected( this[0] ) ) {
+			// Make sure that the elements are removed from the DOM before they are inserted
+			// this can help fix replacing a parent with child elements
+			if ( jQuery.isFunction( value ) ) {
+				return this.each(function(i) {
+					var self = jQuery(this), old = self.html();
+					self.replaceWith( value.call( this, i, old ) );
+				});
+			}
+
+			if ( typeof value !== "string" ) {
+				value = jQuery( value ).detach();
+			}
+
+			return this.each(function() {
+				var next = this.nextSibling,
+					parent = this.parentNode;
+
+				jQuery( this ).remove();
+
+				if ( next ) {
+					jQuery(next).before( value );
+				} else {
+					jQuery(parent).append( value );
+				}
+			});
+		}
+
+		return this.length ?
+			this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+			this;
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, table, callback ) {
+
+		// Flatten any nested arrays
+		args = [].concat.apply( [], args );
+
+		var results, first, fragment, iNoClone,
+			i = 0,
+			value = args[0],
+			scripts = [],
+			l = this.length;
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
+			return this.each(function() {
+				jQuery(this).domManip( args, table, callback );
+			});
+		}
+
+		if ( jQuery.isFunction(value) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				args[0] = value.call( this, i, table ? self.html() : undefined );
+				self.domManip( args, table, callback );
+			});
+		}
+
+		if ( this[0] ) {
+			results = jQuery.buildFragment( args, this, scripts );
+			fragment = results.fragment;
+			first = fragment.firstChild;
+
+			if ( fragment.childNodes.length === 1 ) {
+				fragment = first;
+			}
+
+			if ( first ) {
+				table = table && jQuery.nodeName( first, "tr" );
+
+				// Use the original fragment for the last item instead of the first because it can end up
+				// being emptied incorrectly in certain situations (#8070).
+				// Fragments from the fragment cache must always be cloned and never used in place.
+				for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
+					callback.call(
+						table && jQuery.nodeName( this[i], "table" ) ?
+							findOrAppend( this[i], "tbody" ) :
+							this[i],
+						i === iNoClone ?
+							fragment :
+							jQuery.clone( fragment, true, true )
+					);
+				}
+			}
+
+			// Fix #11809: Avoid leaking memory
+			fragment = first = null;
+
+			if ( scripts.length ) {
+				jQuery.each( scripts, function( i, elem ) {
+					if ( elem.src ) {
+						if ( jQuery.ajax ) {
+							jQuery.ajax({
+								url: elem.src,
+								type: "GET",
+								dataType: "script",
+								async: false,
+								global: false,
+								"throws": true
+							});
+						} else {
+							jQuery.error("no ajax");
+						}
+					} else {
+						jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
+					}
+
+					if ( elem.parentNode ) {
+						elem.parentNode.removeChild( elem );
+					}
+				});
+			}
+		}
+
+		return this;
+	}
+});
+
+function findOrAppend( elem, tag ) {
+	return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
+}
+
+function cloneCopyEvent( src, dest ) {
+
+	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+		return;
+	}
+
+	var type, i, l,
+		oldData = jQuery._data( src ),
+		curData = jQuery._data( dest, oldData ),
+		events = oldData.events;
+
+	if ( events ) {
+		delete curData.handle;
+		curData.events = {};
+
+		for ( type in events ) {
+			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+				jQuery.event.add( dest, type, events[ type ][ i ] );
+			}
+		}
+	}
+
+	// make the cloned public data object a copy from the original
+	if ( curData.data ) {
+		curData.data = jQuery.extend( {}, curData.data );
+	}
+}
+
+function cloneFixAttributes( src, dest ) {
+	var nodeName;
+
+	// We do not need to do anything for non-Elements
+	if ( dest.nodeType !== 1 ) {
+		return;
+	}
+
+	// clearAttributes removes the attributes, which we don't want,
+	// but also removes the attachEvent events, which we *do* want
+	if ( dest.clearAttributes ) {
+		dest.clearAttributes();
+	}
+
+	// mergeAttributes, in contrast, only merges back on the
+	// original attributes, not the events
+	if ( dest.mergeAttributes ) {
+		dest.mergeAttributes( src );
+	}
+
+	nodeName = dest.nodeName.toLowerCase();
+
+	if ( nodeName === "object" ) {
+		// IE6-10 improperly clones children of object elements using classid.
+		// IE10 throws NoModificationAllowedError if parent is null, #12132.
+		if ( dest.parentNode ) {
+			dest.outerHTML = src.outerHTML;
+		}
+
+		// This path appears unavoidable for IE9. When cloning an object
+		// element in IE9, the outerHTML strategy above is not sufficient.
+		// If the src has innerHTML and the destination does not,
+		// copy the src.innerHTML into the dest.innerHTML. #10324
+		if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
+			dest.innerHTML = src.innerHTML;
+		}
+
+	} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+		// IE6-8 fails to persist the checked state of a cloned checkbox
+		// or radio button. Worse, IE6-7 fail to give the cloned element
+		// a checked appearance if the defaultChecked value isn't also set
+
+		dest.defaultChecked = dest.checked = src.checked;
+
+		// IE6-7 get confused and end up setting the value of a cloned
+		// checkbox/radio button to an empty string instead of "on"
+		if ( dest.value !== src.value ) {
+			dest.value = src.value;
+		}
+
+	// IE6-8 fails to return the selected option to the default selected
+	// state when cloning options
+	} else if ( nodeName === "option" ) {
+		dest.selected = src.defaultSelected;
+
+	// IE6-8 fails to set the defaultValue to the correct value when
+	// cloning other types of input fields
+	} else if ( nodeName === "input" || nodeName === "textarea" ) {
+		dest.defaultValue = src.defaultValue;
+
+	// IE blanks contents when cloning scripts
+	} else if ( nodeName === "script" && dest.text !== src.text ) {
+		dest.text = src.text;
+	}
+
+	// Event data gets referenced instead of copied if the expando
+	// gets copied too
+	dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, context, scripts ) {
+	var fragment, cacheable, cachehit,
+		first = args[ 0 ];
+
+	// Set context from what may come in as undefined or a jQuery collection or a node
+	// Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
+	// also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
+	context = context || document;
+	context = !context.nodeType && context[0] || context;
+	context = context.ownerDocument || context;
+
+	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+	// Cloning options loses the selected state, so don't cache them
+	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+	// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+	if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
+		first.charAt(0) === "<" && !rnocache.test( first ) &&
+		(jQuery.support.checkClone || !rchecked.test( first )) &&
+		(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+		// Mark cacheable and look for a hit
+		cacheable = true;
+		fragment = jQuery.fragments[ first ];
+		cachehit = fragment !== undefined;
+	}
+
+	if ( !fragment ) {
+		fragment = context.createDocumentFragment();
+		jQuery.clean( args, context, fragment, scripts );
+
+		// Update the cache, but only store false
+		// unless this is a second parsing of the same content
+		if ( cacheable ) {
+			jQuery.fragments[ first ] = cachehit && fragment;
+		}
+	}
+
+	return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var elems,
+			i = 0,
+			ret = [],
+			insert = jQuery( selector ),
+			l = insert.length,
+			parent = this.length === 1 && this[0].parentNode;
+
+		if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
+			insert[ original ]( this[0] );
+			return this;
+		} else {
+			for ( ; i < l; i++ ) {
+				elems = ( i > 0 ? this.clone(true) : this ).get();
+				jQuery( insert[i] )[ original ]( elems );
+				ret = ret.concat( elems );
+			}
+
+			return this.pushStack( ret, name, insert.selector );
+		}
+	};
+});
+
+function getAll( elem ) {
+	if ( typeof elem.getElementsByTagName !== "undefined" ) {
+		return elem.getElementsByTagName( "*" );
+
+	} else if ( typeof elem.querySelectorAll !== "undefined" ) {
+		return elem.querySelectorAll( "*" );
+
+	} else {
+		return [];
+	}
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+	if ( rcheckableType.test( elem.type ) ) {
+		elem.defaultChecked = elem.checked;
+	}
+}
+
+jQuery.extend({
+	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+		var srcElements,
+			destElements,
+			i,
+			clone;
+
+		if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+			clone = elem.cloneNode( true );
+
+		// IE<=8 does not properly clone detached, unknown element nodes
+		} else {
+			fragmentDiv.innerHTML = elem.outerHTML;
+			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+		}
+
+		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+			// IE copies events bound via attachEvent when using cloneNode.
+			// Calling detachEvent on the clone will also remove the events
+			// from the original. In order to get around this, we use some
+			// proprietary methods to clear the events. Thanks to MooTools
+			// guys for this hotness.
+
+			cloneFixAttributes( elem, clone );
+
+			// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+			srcElements = getAll( elem );
+			destElements = getAll( clone );
+
+			// Weird iteration because IE will replace the length property
+			// with an element if you are cloning the body and one of the
+			// elements on the page has a name or id of "length"
+			for ( i = 0; srcElements[i]; ++i ) {
+				// Ensure that the destination node is not null; Fixes #9587
+				if ( destElements[i] ) {
+					cloneFixAttributes( srcElements[i], destElements[i] );
+				}
+			}
+		}
+
+		// Copy the events from the original to the clone
+		if ( dataAndEvents ) {
+			cloneCopyEvent( elem, clone );
+
+			if ( deepDataAndEvents ) {
+				srcElements = getAll( elem );
+				destElements = getAll( clone );
+
+				for ( i = 0; srcElements[i]; ++i ) {
+					cloneCopyEvent( srcElements[i], destElements[i] );
+				}
+			}
+		}
+
+		srcElements = destElements = null;
+
+		// Return the cloned set
+		return clone;
+	},
+
+	clean: function( elems, context, fragment, scripts ) {
+		var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
+			safe = context === document && safeFragment,
+			ret = [];
+
+		// Ensure that context is a document
+		if ( !context || typeof context.createDocumentFragment === "undefined" ) {
+			context = document;
+		}
+
+		// Use the already-created safe fragment if context permits
+		for ( i = 0; (elem = elems[i]) != null; i++ ) {
+			if ( typeof elem === "number" ) {
+				elem += "";
+			}
+
+			if ( !elem ) {
+				continue;
+			}
+
+			// Convert html string into DOM nodes
+			if ( typeof elem === "string" ) {
+				if ( !rhtml.test( elem ) ) {
+					elem = context.createTextNode( elem );
+				} else {
+					// Ensure a safe container in which to render the html
+					safe = safe || createSafeFragment( context );
+					div = context.createElement("div");
+					safe.appendChild( div );
+
+					// Fix "XHTML"-style tags in all browsers
+					elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+					// Go to html and back, then peel off extra wrappers
+					tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+					wrap = wrapMap[ tag ] || wrapMap._default;
+					depth = wrap[0];
+					div.innerHTML = wrap[1] + elem + wrap[2];
+
+					// Move to the right depth
+					while ( depth-- ) {
+						div = div.lastChild;
+					}
+
+					// Remove IE's autoinserted <tbody> from table fragments
+					if ( !jQuery.support.tbody ) {
+
+						// String was a <table>, *may* have spurious <tbody>
+						hasBody = rtbody.test(elem);
+							tbody = tag === "table" && !hasBody ?
+								div.firstChild && div.firstChild.childNodes :
+
+								// String was a bare <thead> or <tfoot>
+								wrap[1] === "<table>" && !hasBody ?
+									div.childNodes :
+									[];
+
+						for ( j = tbody.length - 1; j >= 0 ; --j ) {
+							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+								tbody[ j ].parentNode.removeChild( tbody[ j ] );
+							}
+						}
+					}
+
+					// IE completely kills leading whitespace when innerHTML is used
+					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+					}
+
+					elem = div.childNodes;
+
+					// Take out of fragment container (we need a fresh div each time)
+					div.parentNode.removeChild( div );
+				}
+			}
+
+			if ( elem.nodeType ) {
+				ret.push( elem );
+			} else {
+				jQuery.merge( ret, elem );
+			}
+		}
+
+		// Fix #11356: Clear elements from safeFragment
+		if ( div ) {
+			elem = div = safe = null;
+		}
+
+		// Reset defaultChecked for any radios and checkboxes
+		// about to be appended to the DOM in IE 6/7 (#8060)
+		if ( !jQuery.support.appendChecked ) {
+			for ( i = 0; (elem = ret[i]) != null; i++ ) {
+				if ( jQuery.nodeName( elem, "input" ) ) {
+					fixDefaultChecked( elem );
+				} else if ( typeof elem.getElementsByTagName !== "undefined" ) {
+					jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+				}
+			}
+		}
+
+		// Append elements to a provided document fragment
+		if ( fragment ) {
+			// Special handling of each script element
+			handleScript = function( elem ) {
+				// Check if we consider it executable
+				if ( !elem.type || rscriptType.test( elem.type ) ) {
+					// Detach the script and store it in the scripts array (if provided) or the fragment
+					// Return truthy to indicate that it has been handled
+					return scripts ?
+						scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+						fragment.appendChild( elem );
+				}
+			};
+
+			for ( i = 0; (elem = ret[i]) != null; i++ ) {
+				// Check if we're done after handling an executable script
+				if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+					// Append to fragment and handle embedded scripts
+					fragment.appendChild( elem );
+					if ( typeof elem.getElementsByTagName !== "undefined" ) {
+						// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+						jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+						// Splice the scripts into ret after their former ancestor and advance our index beyond them
+						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+						i += jsTags.length;
+					}
+				}
+			}
+		}
+
+		return ret;
+	},
+
+	cleanData: function( elems, /* internal */ acceptData ) {
+		var data, id, elem, type,
+			i = 0,
+			internalKey = jQuery.expando,
+			cache = jQuery.cache,
+			deleteExpando = jQuery.support.deleteExpando,
+			special = jQuery.event.special;
+
+		for ( ; (elem = elems[i]) != null; i++ ) {
+
+			if ( acceptData || jQuery.acceptData( elem ) ) {
+
+				id = elem[ internalKey ];
+				data = id && cache[ id ];
+
+				if ( data ) {
+					if ( data.events ) {
+						for ( type in data.events ) {
+							if ( special[ type ] ) {
+								jQuery.event.remove( elem, type );
+
+							// This is a shortcut to avoid jQuery.event.remove's overhead
+							} else {
+								jQuery.removeEvent( elem, type, data.handle );
+							}
+						}
+					}
+
+					// Remove cache only if it was not already removed by jQuery.event.remove
+					if ( cache[ id ] ) {
+
+						delete cache[ id ];
+
+						// IE does not allow us to delete expando properties from nodes,
+						// nor does it have a removeAttribute function on Document nodes;
+						// we must handle all of these cases
+						if ( deleteExpando ) {
+							delete elem[ internalKey ];
+
+						} else if ( elem.removeAttribute ) {
+							elem.removeAttribute( internalKey );
+
+						} else {
+							elem[ internalKey ] = null;
+						}
+
+						jQuery.deletedIds.push( id );
+					}
+				}
+			}
+		}
+	}
+});
+// Limit scope pollution from any deprecated API
+(function() {
+
+var matched, browser;
+
+// Use of jQuery.browser is frowned upon.
+// More details: http://api.jquery.com/jQuery.browser
+// jQuery.uaMatch maintained for back-compat
+jQuery.uaMatch = function( ua ) {
+	ua = ua.toLowerCase();
+
+	var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+		/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+		/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+		/(msie) ([\w.]+)/.exec( ua ) ||
+		ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+		[];
+
+	return {
+		browser: match[ 1 ] || "",
+		version: match[ 2 ] || "0"
+	};
+};
+
+matched = jQuery.uaMatch( navigator.userAgent );
+browser = {};
+
+if ( matched.browser ) {
+	browser[ matched.browser ] = true;
+	browser.version = matched.version;
+}
+
+// Chrome is Webkit, but Webkit is also Safari.
+if ( browser.chrome ) {
+	browser.webkit = true;
+} else if ( browser.webkit ) {
+	browser.safari = true;
+}
+
+jQuery.browser = browser;
+
+jQuery.sub = function() {
+	function jQuerySub( selector, context ) {
+		return new jQuerySub.fn.init( selector, context );
+	}
+	jQuery.extend( true, jQuerySub, this );
+	jQuerySub.superclass = this;
+	jQuerySub.fn = jQuerySub.prototype = this();
+	jQuerySub.fn.constructor = jQuerySub;
+	jQuerySub.sub = this.sub;
+	jQuerySub.fn.init = function init( selector, context ) {
+		if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+			context = jQuerySub( context );
+		}
+
+		return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+	};
+	jQuerySub.fn.init.prototype = jQuerySub.fn;
+	var rootjQuerySub = jQuerySub(document);
+	return jQuerySub;
+};
+
+})();
+var curCSS, iframe, iframeDoc,
+	ralpha = /alpha\([^)]*\)/i,
+	ropacity = /opacity=([^)]*)/,
+	rposition = /^(top|right|bottom|left)$/,
+	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+	rmargin = /^margin/,
+	rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+	rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+	rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
+	elemdisplay = { BODY: "block" },
+
+	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+	cssNormalTransform = {
+		letterSpacing: 0,
+		fontWeight: 400
+	},
+
+	cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
+
+	eventsToggle = jQuery.fn.toggle;
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+	// shortcut for names that are not vendor prefixed
+	if ( name in style ) {
+		return name;
+	}
+
+	// check for vendor prefixed names
+	var capName = name.charAt(0).toUpperCase() + name.slice(1),
+		origName = name,
+		i = cssPrefixes.length;
+
+	while ( i-- ) {
+		name = cssPrefixes[ i ] + capName;
+		if ( name in style ) {
+			return name;
+		}
+	}
+
+	return origName;
+}
+
+function isHidden( elem, el ) {
+	elem = el || elem;
+	return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+function showHide( elements, show ) {
+	var elem, display,
+		values = [],
+		index = 0,
+		length = elements.length;
+
+	for ( ; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		values[ index ] = jQuery._data( elem, "olddisplay" );
+		if ( show ) {
+			// Reset the inline display of this element to learn if it is
+			// being hidden by cascaded rules or not
+			if ( !values[ index ] && elem.style.display === "none" ) {
+				elem.style.display = "";
+			}
+
+			// Set elements which have been overridden with display: none
+			// in a stylesheet to whatever the default browser style is
+			// for such an element
+			if ( elem.style.display === "" && isHidden( elem ) ) {
+				values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+			}
+		} else {
+			display = curCSS( elem, "display" );
+
+			if ( !values[ index ] && display !== "none" ) {
+				jQuery._data( elem, "olddisplay", display );
+			}
+		}
+	}
+
+	// Set the display of most of the elements in a second loop
+	// to avoid the constant reflow
+	for ( index = 0; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+			elem.style.display = show ? values[ index ] || "" : "none";
+		}
+	}
+
+	return elements;
+}
+
+jQuery.fn.extend({
+	css: function( name, value ) {
+		return jQuery.access( this, function( elem, name, value ) {
+			return value !== undefined ?
+				jQuery.style( elem, name, value ) :
+				jQuery.css( elem, name );
+		}, name, value, arguments.length > 1 );
+	},
+	show: function() {
+		return showHide( this, true );
+	},
+	hide: function() {
+		return showHide( this );
+	},
+	toggle: function( state, fn2 ) {
+		var bool = typeof state === "boolean";
+
+		if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
+			return eventsToggle.apply( this, arguments );
+		}
+
+		return this.each(function() {
+			if ( bool ? state : isHidden( this ) ) {
+				jQuery( this ).show();
+			} else {
+				jQuery( this ).hide();
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	// Add in style property hooks for overriding the default
+	// behavior of getting and setting a style property
+	cssHooks: {
+		opacity: {
+			get: function( elem, computed ) {
+				if ( computed ) {
+					// We should always get a number back from opacity
+					var ret = curCSS( elem, "opacity" );
+					return ret === "" ? "1" : ret;
+
+				}
+			}
+		}
+	},
+
+	// Exclude the following css properties to add px
+	cssNumber: {
+		"fillOpacity": true,
+		"fontWeight": true,
+		"lineHeight": true,
+		"opacity": true,
+		"orphans": true,
+		"widows": true,
+		"zIndex": true,
+		"zoom": true
+	},
+
+	// Add in properties whose names you wish to fix before
+	// setting or getting the value
+	cssProps: {
+		// normalize float css property
+		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+	},
+
+	// Get and set the style property on a DOM Node
+	style: function( elem, name, value, extra ) {
+		// Don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+			return;
+		}
+
+		// Make sure that we're working with the right name
+		var ret, type, hooks,
+			origName = jQuery.camelCase( name ),
+			style = elem.style;
+
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// Check if we're setting a value
+		if ( value !== undefined ) {
+			type = typeof value;
+
+			// convert relative number strings (+= or -=) to relative numbers. #7345
+			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+				// Fixes bug #9237
+				type = "number";
+			}
+
+			// Make sure that NaN and null values aren't set. See: #7116
+			if ( value == null || type === "number" && isNaN( value ) ) {
+				return;
+			}
+
+			// If a number was passed in, add 'px' to the (except for certain CSS properties)
+			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+				value += "px";
+			}
+
+			// If a hook was provided, use that value, otherwise just set the specified value
+			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+				// Fixes bug #5509
+				try {
+					style[ name ] = value;
+				} catch(e) {}
+			}
+
+		} else {
+			// If a hook was provided get the non-computed value from there
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+				return ret;
+			}
+
+			// Otherwise just get the value from the style object
+			return style[ name ];
+		}
+	},
+
+	css: function( elem, name, numeric, extra ) {
+		var val, num, hooks,
+			origName = jQuery.camelCase( name );
+
+		// Make sure that we're working with the right name
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// If a hook was provided get the computed value from there
+		if ( hooks && "get" in hooks ) {
+			val = hooks.get( elem, true, extra );
+		}
+
+		// Otherwise, if a way to get the computed value exists, use that
+		if ( val === undefined ) {
+			val = curCSS( elem, name );
+		}
+
+		//convert "normal" to computed value
+		if ( val === "normal" && name in cssNormalTransform ) {
+			val = cssNormalTransform[ name ];
+		}
+
+		// Return, converting to number if forced or a qualifier was provided and val looks numeric
+		if ( numeric || extra !== undefined ) {
+			num = parseFloat( val );
+			return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
+		}
+		return val;
+	},
+
+	// A method for quickly swapping in/out CSS properties to get correct calculations
+	swap: function( elem, options, callback ) {
+		var ret, name,
+			old = {};
+
+		// Remember the old values, and insert the new ones
+		for ( name in options ) {
+			old[ name ] = elem.style[ name ];
+			elem.style[ name ] = options[ name ];
+		}
+
+		ret = callback.call( elem );
+
+		// Revert the old values
+		for ( name in options ) {
+			elem.style[ name ] = old[ name ];
+		}
+
+		return ret;
+	}
+});
+
+// NOTE: To any future maintainer, we've window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+	curCSS = function( elem, name ) {
+		var ret, width, minWidth, maxWidth,
+			computed = window.getComputedStyle( elem, null ),
+			style = elem.style;
+
+		if ( computed ) {
+
+			// getPropertyValue is only needed for .css('filter') in IE9, see #12537
+			ret = computed.getPropertyValue( name ) || computed[ name ];
+
+			if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+				ret = jQuery.style( elem, name );
+			}
+
+			// A tribute to the "awesome hack by Dean Edwards"
+			// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+			// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+			// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+			if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+				width = style.width;
+				minWidth = style.minWidth;
+				maxWidth = style.maxWidth;
+
+				style.minWidth = style.maxWidth = style.width = ret;
+				ret = computed.width;
+
+				style.width = width;
+				style.minWidth = minWidth;
+				style.maxWidth = maxWidth;
+			}
+		}
+
+		return ret;
+	};
+} else if ( document.documentElement.currentStyle ) {
+	curCSS = function( elem, name ) {
+		var left, rsLeft,
+			ret = elem.currentStyle && elem.currentStyle[ name ],
+			style = elem.style;
+
+		// Avoid setting ret to empty string here
+		// so we don't default to auto
+		if ( ret == null && style && style[ name ] ) {
+			ret = style[ name ];
+		}
+
+		// From the awesome hack by Dean Edwards
+		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+		// If we're not dealing with a regular pixel number
+		// but a number that has a weird ending, we need to convert it to pixels
+		// but not position css attributes, as those are proportional to the parent element instead
+		// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+			// Remember the original values
+			left = style.left;
+			rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+			// Put in the new values to get a computed value out
+			if ( rsLeft ) {
+				elem.runtimeStyle.left = elem.currentStyle.left;
+			}
+			style.left = name === "fontSize" ? "1em" : ret;
+			ret = style.pixelLeft + "px";
+
+			// Revert the changed values
+			style.left = left;
+			if ( rsLeft ) {
+				elem.runtimeStyle.left = rsLeft;
+			}
+		}
+
+		return ret === "" ? "auto" : ret;
+	};
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+	var matches = rnumsplit.exec( value );
+	return matches ?
+			Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+			value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
+	var i = extra === ( isBorderBox ? "border" : "content" ) ?
+		// If we already have the right measurement, avoid augmentation
+		4 :
+		// Otherwise initialize for horizontal or vertical properties
+		name === "width" ? 1 : 0,
+
+		val = 0;
+
+	for ( ; i < 4; i += 2 ) {
+		// both box models exclude margin, so add it if we want it
+		if ( extra === "margin" ) {
+			// we use jQuery.css instead of curCSS here
+			// because of the reliableMarginRight CSS hook!
+			val += jQuery.css( elem, extra + cssExpand[ i ], true );
+		}
+
+		// From this point on we use curCSS for maximum performance (relevant in animations)
+		if ( isBorderBox ) {
+			// border-box includes padding, so remove it if we want content
+			if ( extra === "content" ) {
+				val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+			}
+
+			// at this point, extra isn't border nor margin, so remove border
+			if ( extra !== "margin" ) {
+				val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+			}
+		} else {
+			// at this point, extra isn't content, so add padding
+			val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
+
+			// at this point, extra isn't content nor padding, so add border
+			if ( extra !== "padding" ) {
+				val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+			}
+		}
+	}
+
+	return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+	// Start with offset property, which is equivalent to the border-box value
+	var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+		valueIsBorderBox = true,
+		isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
+
+	// some non-html elements return undefined for offsetWidth, so check for null/undefined
+	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+	if ( val <= 0 || val == null ) {
+		// Fall back to computed then uncomputed css if necessary
+		val = curCSS( elem, name );
+		if ( val < 0 || val == null ) {
+			val = elem.style[ name ];
+		}
+
+		// Computed unit is not pixels. Stop here and return.
+		if ( rnumnonpx.test(val) ) {
+			return val;
+		}
+
+		// we need the check for style in case a browser which returns unreliable values
+		// for getComputedStyle silently falls back to the reliable elem.style
+		valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+		// Normalize "", auto, and prepare for extra
+		val = parseFloat( val ) || 0;
+	}
+
+	// use the active box-sizing model to add/subtract irrelevant styles
+	return ( val +
+		augmentWidthOrHeight(
+			elem,
+			name,
+			extra || ( isBorderBox ? "border" : "content" ),
+			valueIsBorderBox
+		)
+	) + "px";
+}
+
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+	if ( elemdisplay[ nodeName ] ) {
+		return elemdisplay[ nodeName ];
+	}
+
+	var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
+		display = elem.css("display");
+	elem.remove();
+
+	// If the simple way fails,
+	// get element's real default display by attaching it to a temp iframe
+	if ( display === "none" || display === "" ) {
+		// Use the already-created iframe if possible
+		iframe = document.body.appendChild(
+			iframe || jQuery.extend( document.createElement("iframe"), {
+				frameBorder: 0,
+				width: 0,
+				height: 0
+			})
+		);
+
+		// Create a cacheable copy of the iframe document on first call.
+		// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+		// document to it; WebKit & Firefox won't allow reusing the iframe document.
+		if ( !iframeDoc || !iframe.createElement ) {
+			iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+			iframeDoc.write("<!doctype html><html><body>");
+			iframeDoc.close();
+		}
+
+		elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
+
+		display = curCSS( elem, "display" );
+		document.body.removeChild( iframe );
+	}
+
+	// Store the correct default display
+	elemdisplay[ nodeName ] = display;
+
+	return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+	jQuery.cssHooks[ name ] = {
+		get: function( elem, computed, extra ) {
+			if ( computed ) {
+				// certain elements can have dimension info if we invisibly show them
+				// however, it must have a current display style that would benefit from this
+				if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
+					return jQuery.swap( elem, cssShow, function() {
+						return getWidthOrHeight( elem, name, extra );
+					});
+				} else {
+					return getWidthOrHeight( elem, name, extra );
+				}
+			}
+		},
+
+		set: function( elem, value, extra ) {
+			return setPositiveNumber( elem, value, extra ?
+				augmentWidthOrHeight(
+					elem,
+					name,
+					extra,
+					jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
+				) : 0
+			);
+		}
+	};
+});
+
+if ( !jQuery.support.opacity ) {
+	jQuery.cssHooks.opacity = {
+		get: function( elem, computed ) {
+			// IE uses filters for opacity
+			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+				( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+				computed ? "1" : "";
+		},
+
+		set: function( elem, value ) {
+			var style = elem.style,
+				currentStyle = elem.currentStyle,
+				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+				filter = currentStyle && currentStyle.filter || style.filter || "";
+
+			// IE has trouble with opacity if it does not have layout
+			// Force it by setting the zoom level
+			style.zoom = 1;
+
+			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+			if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+				style.removeAttribute ) {
+
+				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+				// if "filter:" is present at all, clearType is disabled, we want to avoid this
+				// style.removeAttribute is IE Only, but so apparently is this code path...
+				style.removeAttribute( "filter" );
+
+				// if there there is no filter style applied in a css rule, we are done
+				if ( currentStyle && !currentStyle.filter ) {
+					return;
+				}
+			}
+
+			// otherwise, set new filter values
+			style.filter = ralpha.test( filter ) ?
+				filter.replace( ralpha, opacity ) :
+				filter + " " + opacity;
+		}
+	};
+}
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+	if ( !jQuery.support.reliableMarginRight ) {
+		jQuery.cssHooks.marginRight = {
+			get: function( elem, computed ) {
+				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+				// Work around by temporarily setting element display to inline-block
+				return jQuery.swap( elem, { "display": "inline-block" }, function() {
+					if ( computed ) {
+						return curCSS( elem, "marginRight" );
+					}
+				});
+			}
+		};
+	}
+
+	// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+	// getComputedStyle returns percent when specified for top/left/bottom/right
+	// rather than make the css module depend on the offset module, we just check for it here
+	if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+		jQuery.each( [ "top", "left" ], function( i, prop ) {
+			jQuery.cssHooks[ prop ] = {
+				get: function( elem, computed ) {
+					if ( computed ) {
+						var ret = curCSS( elem, prop );
+						// if curCSS returns percentage, fallback to offset
+						return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
+					}
+				}
+			};
+		});
+	}
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.hidden = function( elem ) {
+		return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
+	};
+
+	jQuery.expr.filters.visible = function( elem ) {
+		return !jQuery.expr.filters.hidden( elem );
+	};
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+	margin: "",
+	padding: "",
+	border: "Width"
+}, function( prefix, suffix ) {
+	jQuery.cssHooks[ prefix + suffix ] = {
+		expand: function( value ) {
+			var i,
+
+				// assumes a single number if not a string
+				parts = typeof value === "string" ? value.split(" ") : [ value ],
+				expanded = {};
+
+			for ( i = 0; i < 4; i++ ) {
+				expanded[ prefix + cssExpand[ i ] + suffix ] =
+					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+			}
+
+			return expanded;
+		}
+	};
+
+	if ( !rmargin.test( prefix ) ) {
+		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+	}
+});
+var r20 = /%20/g,
+	rbracket = /\[\]$/,
+	rCRLF = /\r?\n/g,
+	rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+	rselectTextarea = /^(?:select|textarea)/i;
+
+jQuery.fn.extend({
+	serialize: function() {
+		return jQuery.param( this.serializeArray() );
+	},
+	serializeArray: function() {
+		return this.map(function(){
+			return this.elements ? jQuery.makeArray( this.elements ) : this;
+		})
+		.filter(function(){
+			return this.name && !this.disabled &&
+				( this.checked || rselectTextarea.test( this.nodeName ) ||
+					rinput.test( this.type ) );
+		})
+		.map(function( i, elem ){
+			var val = jQuery( this ).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray( val ) ?
+					jQuery.map( val, function( val, i ){
+						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+					}) :
+					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+		}).get();
+	}
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+	var prefix,
+		s = [],
+		add = function( key, value ) {
+			// If value is a function, invoke it and return its value
+			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+		};
+
+	// Set traditional to true for jQuery <= 1.3.2 behavior.
+	if ( traditional === undefined ) {
+		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+	}
+
+	// If an array was passed in, assume that it is an array of form elements.
+	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+		// Serialize the form elements
+		jQuery.each( a, function() {
+			add( this.name, this.value );
+		});
+
+	} else {
+		// If traditional, encode the "old" way (the way 1.3.2 or older
+		// did it), otherwise encode params recursively.
+		for ( prefix in a ) {
+			buildParams( prefix, a[ prefix ], traditional, add );
+		}
+	}
+
+	// Return the resulting serialization
+	return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+	var name;
+
+	if ( jQuery.isArray( obj ) ) {
+		// Serialize array item.
+		jQuery.each( obj, function( i, v ) {
+			if ( traditional || rbracket.test( prefix ) ) {
+				// Treat each array item as a scalar.
+				add( prefix, v );
+
+			} else {
+				// If array item is non-scalar (array or object), encode its
+				// numeric index to resolve deserialization ambiguity issues.
+				// Note that rack (as of 1.0.0) can't currently deserialize
+				// nested arrays properly, and attempting to do so may cause
+				// a server error. Possible fixes are to modify rack's
+				// deserialization algorithm or to provide an option or flag
+				// to force array serialization to be shallow.
+				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+			}
+		});
+
+	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
+		// Serialize object item.
+		for ( name in obj ) {
+			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+		}
+
+	} else {
+		// Serialize scalar item.
+		add( prefix, obj );
+	}
+}
+var
+	// Document location
+	ajaxLocParts,
+	ajaxLocation,
+
+	rhash = /#.*$/,
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+	rnoContent = /^(?:GET|HEAD)$/,
+	rprotocol = /^\/\//,
+	rquery = /\?/,
+	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+	rts = /([?&])_=[^&]*/,
+	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+	// Keep a copy of the old load method
+	_load = jQuery.fn.load,
+
+	/* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+	prefilters = {},
+
+	/* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+	transports = {},
+
+	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+	allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+	ajaxLocation = location.href;
+} catch( e ) {
+	// Use the href attribute of an A element
+	// since IE will modify it given document.location
+	ajaxLocation = document.createElement( "a" );
+	ajaxLocation.href = "";
+	ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+	// dataTypeExpression is optional and defaults to "*"
+	return function( dataTypeExpression, func ) {
+
+		if ( typeof dataTypeExpression !== "string" ) {
+			func = dataTypeExpression;
+			dataTypeExpression = "*";
+		}
+
+		var dataType, list, placeBefore,
+			dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ),
+			i = 0,
+			length = dataTypes.length;
+
+		if ( jQuery.isFunction( func ) ) {
+			// For each dataType in the dataTypeExpression
+			for ( ; i < length; i++ ) {
+				dataType = dataTypes[ i ];
+				// We control if we're asked to add before
+				// any existing element
+				placeBefore = /^\+/.test( dataType );
+				if ( placeBefore ) {
+					dataType = dataType.substr( 1 ) || "*";
+				}
+				list = structure[ dataType ] = structure[ dataType ] || [];
+				// then we add to the structure accordingly
+				list[ placeBefore ? "unshift" : "push" ]( func );
+			}
+		}
+	};
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+		dataType /* internal */, inspected /* internal */ ) {
+
+	dataType = dataType || options.dataTypes[ 0 ];
+	inspected = inspected || {};
+
+	inspected[ dataType ] = true;
+
+	var selection,
+		list = structure[ dataType ],
+		i = 0,
+		length = list ? list.length : 0,
+		executeOnly = ( structure === prefilters );
+
+	for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+		selection = list[ i ]( options, originalOptions, jqXHR );
+		// If we got redirected to another dataType
+		// we try there if executing only and not done already
+		if ( typeof selection === "string" ) {
+			if ( !executeOnly || inspected[ selection ] ) {
+				selection = undefined;
+			} else {
+				options.dataTypes.unshift( selection );
+				selection = inspectPrefiltersOrTransports(
+						structure, options, originalOptions, jqXHR, selection, inspected );
+			}
+		}
+	}
+	// If we're only executing or nothing was selected
+	// we try the catchall dataType if not done already
+	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+		selection = inspectPrefiltersOrTransports(
+				structure, options, originalOptions, jqXHR, "*", inspected );
+	}
+	// unnecessary when only executing (prefilters)
+	// but it'll be ignored by the caller in that case
+	return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+	var key, deep,
+		flatOptions = jQuery.ajaxSettings.flatOptions || {};
+	for ( key in src ) {
+		if ( src[ key ] !== undefined ) {
+			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+		}
+	}
+	if ( deep ) {
+		jQuery.extend( true, target, deep );
+	}
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+	if ( typeof url !== "string" && _load ) {
+		return _load.apply( this, arguments );
+	}
+
+	// Don't do a request if no elements are being requested
+	if ( !this.length ) {
+		return this;
+	}
+
+	var selector, type, response,
+		self = this,
+		off = url.indexOf(" ");
+
+	if ( off >= 0 ) {
+		selector = url.slice( off, url.length );
+		url = url.slice( 0, off );
+	}
+
+	// If it's a function
+	if ( jQuery.isFunction( params ) ) {
+
+		// We assume that it's the callback
+		callback = params;
+		params = undefined;
+
+	// Otherwise, build a param string
+	} else if ( params && typeof params === "object" ) {
+		type = "POST";
+	}
+
+	// Request the remote document
+	jQuery.ajax({
+		url: url,
+
+		// if "type" variable is undefined, then "GET" method will be used
+		type: type,
+		dataType: "html",
+		data: params,
+		complete: function( jqXHR, status ) {
+			if ( callback ) {
+				self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+			}
+		}
+	}).done(function( responseText ) {
+
+		// Save response for use in complete callback
+		response = arguments;
+
+		// See if a selector was specified
+		self.html( selector ?
+
+			// Create a dummy div to hold the results
+			jQuery("<div>")
+
+				// inject the contents of the document in, removing the scripts
+				// to avoid any 'Permission Denied' errors in IE
+				.append( responseText.replace( rscript, "" ) )
+
+				// Locate the specified elements
+				.find( selector ) :
+
+			// If not, just inject the full result
+			responseText );
+
+	});
+
+	return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+	jQuery.fn[ o ] = function( f ){
+		return this.on( o, f );
+	};
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+	jQuery[ method ] = function( url, data, callback, type ) {
+		// shift arguments if data argument was omitted
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = undefined;
+		}
+
+		return jQuery.ajax({
+			type: method,
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	};
+});
+
+jQuery.extend({
+
+	getScript: function( url, callback ) {
+		return jQuery.get( url, undefined, callback, "script" );
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get( url, data, callback, "json" );
+	},
+
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function( target, settings ) {
+		if ( settings ) {
+			// Building a settings object
+			ajaxExtend( target, jQuery.ajaxSettings );
+		} else {
+			// Extending ajaxSettings
+			settings = target;
+			target = jQuery.ajaxSettings;
+		}
+		ajaxExtend( target, settings );
+		return target;
+	},
+
+	ajaxSettings: {
+		url: ajaxLocation,
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+		global: true,
+		type: "GET",
+		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+		processData: true,
+		async: true,
+		/*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		throws: false,
+		traditional: false,
+		headers: {},
+		*/
+
+		accepts: {
+			xml: "application/xml, text/xml",
+			html: "text/html",
+			text: "text/plain",
+			json: "application/json, text/javascript",
+			"*": allTypes
+		},
+
+		contents: {
+			xml: /xml/,
+			html: /html/,
+			json: /json/
+		},
+
+		responseFields: {
+			xml: "responseXML",
+			text: "responseText"
+		},
+
+		// List of data converters
+		// 1) key format is "source_type destination_type" (a single space in-between)
+		// 2) the catchall symbol "*" can be used for source_type
+		converters: {
+
+			// Convert anything to text
+			"* text": window.String,
+
+			// Text to html (true = no transformation)
+			"text html": true,
+
+			// Evaluate text as a json expression
+			"text json": jQuery.parseJSON,
+
+			// Parse text as xml
+			"text xml": jQuery.parseXML
+		},
+
+		// For options that shouldn't be deep extended:
+		// you can add your own custom options here if
+		// and when you create one that shouldn't be
+		// deep extended (see ajaxExtend)
+		flatOptions: {
+			context: true,
+			url: true
+		}
+	},
+
+	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+	ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+	// Main method
+	ajax: function( url, options ) {
+
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
+			options = url;
+			url = undefined;
+		}
+
+		// Force options to be an object
+		options = options || {};
+
+		var // ifModified key
+			ifModifiedKey,
+			// Response headers
+			responseHeadersString,
+			responseHeaders,
+			// transport
+			transport,
+			// timeout handle
+			timeoutTimer,
+			// Cross-domain detection vars
+			parts,
+			// To know if global events are to be dispatched
+			fireGlobals,
+			// Loop variable
+			i,
+			// Create the final options object
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events
+			// It's the callbackContext if one was provided in the options
+			// and if it's a DOM node or a jQuery collection
+			globalEventContext = callbackContext !== s &&
+				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+						jQuery( callbackContext ) : jQuery.event,
+			// Deferreds
+			deferred = jQuery.Deferred(),
+			completeDeferred = jQuery.Callbacks( "once memory" ),
+			// Status-dependent callbacks
+			statusCode = s.statusCode || {},
+			// Headers (they are sent all at once)
+			requestHeaders = {},
+			requestHeadersNames = {},
+			// The jqXHR state
+			state = 0,
+			// Default abort message
+			strAbort = "canceled",
+			// Fake xhr
+			jqXHR = {
+
+				readyState: 0,
+
+				// Caches the header
+				setRequestHeader: function( name, value ) {
+					if ( !state ) {
+						var lname = name.toLowerCase();
+						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+						requestHeaders[ name ] = value;
+					}
+					return this;
+				},
+
+				// Raw string
+				getAllResponseHeaders: function() {
+					return state === 2 ? responseHeadersString : null;
+				},
+
+				// Builds headers hashtable if needed
+				getResponseHeader: function( key ) {
+					var match;
+					if ( state === 2 ) {
+						if ( !responseHeaders ) {
+							responseHeaders = {};
+							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+							}
+						}
+						match = responseHeaders[ key.toLowerCase() ];
+					}
+					return match === undefined ? null : match;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
+				},
+
+				// Cancel the request
+				abort: function( statusText ) {
+					statusText = statusText || strAbort;
+					if ( transport ) {
+						transport.abort( statusText );
+					}
+					done( 0, statusText );
+					return this;
+				}
+			};
+
+		// Callback for when everything is done
+		// It is defined here because jslint complains if it is declared
+		// at the end of the function (which would be more logical and readable)
+		function done( status, nativeStatusText, responses, headers ) {
+			var isSuccess, success, error, response, modified,
+				statusText = nativeStatusText;
+
+			// Called once
+			if ( state === 2 ) {
+				return;
+			}
+
+			// State is "done" now
+			state = 2;
+
+			// Clear timeout if it exists
+			if ( timeoutTimer ) {
+				clearTimeout( timeoutTimer );
+			}
+
+			// Dereference transport for early garbage collection
+			// (no matter how long the jqXHR object will be used)
+			transport = undefined;
+
+			// Cache response headers
+			responseHeadersString = headers || "";
+
+			// Set readyState
+			jqXHR.readyState = status > 0 ? 4 : 0;
+
+			// Get response data
+			if ( responses ) {
+				response = ajaxHandleResponses( s, jqXHR, responses );
+			}
+
+			// If successful, handle type chaining
+			if ( status >= 200 && status < 300 || status === 304 ) {
+
+				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+				if ( s.ifModified ) {
+
+					modified = jqXHR.getResponseHeader("Last-Modified");
+					if ( modified ) {
+						jQuery.lastModified[ ifModifiedKey ] = modified;
+					}
+					modified = jqXHR.getResponseHeader("Etag");
+					if ( modified ) {
+						jQuery.etag[ ifModifiedKey ] = modified;
+					}
+				}
+
+				// If not modified
+				if ( status === 304 ) {
+
+					statusText = "notmodified";
+					isSuccess = true;
+
+				// If we have data
+				} else {
+
+					isSuccess = ajaxConvert( s, response );
+					statusText = isSuccess.state;
+					success = isSuccess.data;
+					error = isSuccess.error;
+					isSuccess = !error;
+				}
+			} else {
+				// We extract error from statusText
+				// then normalize statusText and status for non-aborts
+				error = statusText;
+				if ( !statusText || status ) {
+					statusText = "error";
+					if ( status < 0 ) {
+						status = 0;
+					}
+				}
+			}
+
+			// Set data for the fake xhr object
+			jqXHR.status = status;
+			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+			// Success/Error
+			if ( isSuccess ) {
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+			} else {
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+			}
+
+			// Status-dependent callbacks
+			jqXHR.statusCode( statusCode );
+			statusCode = undefined;
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+						[ jqXHR, s, isSuccess ? success : error ] );
+			}
+
+			// Complete
+			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+				// Handle the global AJAX counter
+				if ( !( --jQuery.active ) ) {
+					jQuery.event.trigger( "ajaxStop" );
+				}
+			}
+		}
+
+		// Attach deferreds
+		deferred.promise( jqXHR );
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+		jqXHR.complete = completeDeferred.add;
+
+		// Status-dependent callbacks
+		jqXHR.statusCode = function( map ) {
+			if ( map ) {
+				var tmp;
+				if ( state < 2 ) {
+					for ( tmp in map ) {
+						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+					}
+				} else {
+					tmp = map[ jqXHR.status ];
+					jqXHR.always( tmp );
+				}
+			}
+			return this;
+		};
+
+		// Remove hash character (#7531: and string promotion)
+		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+		// We also use the url parameter if available
+		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+		// Extract dataTypes list
+		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
+
+		// A cross-domain request is in order when we have a protocol:host:port mismatch
+		if ( s.crossDomain == null ) {
+			parts = rurl.exec( s.url.toLowerCase() );
+			s.crossDomain = !!( parts &&
+				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+			);
+		}
+
+		// Convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Apply prefilters
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefilter, stop there
+		if ( state === 2 ) {
+			return jqXHR;
+		}
+
+		// We can fire global events as of now if asked to
+		fireGlobals = s.global;
+
+		// Uppercase the type
+		s.type = s.type.toUpperCase();
+
+		// Determine if request has content
+		s.hasContent = !rnoContent.test( s.type );
+
+		// Watch for a new set of requests
+		if ( fireGlobals && jQuery.active++ === 0 ) {
+			jQuery.event.trigger( "ajaxStart" );
+		}
+
+		// More options handling for requests with no content
+		if ( !s.hasContent ) {
+
+			// If data is available, append data to url
+			if ( s.data ) {
+				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+				// #9682: remove data so that it's not used in an eventual retry
+				delete s.data;
+			}
+
+			// Get ifModifiedKey before adding the anti-cache parameter
+			ifModifiedKey = s.url;
+
+			// Add anti-cache in url if needed
+			if ( s.cache === false ) {
+
+				var ts = jQuery.now(),
+					// try replacing _= if it is there
+					ret = s.url.replace( rts, "$1_=" + ts );
+
+				// if nothing was replaced, add timestamp to the end
+				s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+			}
+		}
+
+		// Set the correct header, if data is being sent
+		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+			jqXHR.setRequestHeader( "Content-Type", s.contentType );
+		}
+
+		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+		if ( s.ifModified ) {
+			ifModifiedKey = ifModifiedKey || s.url;
+			if ( jQuery.lastModified[ ifModifiedKey ] ) {
+				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+			}
+			if ( jQuery.etag[ ifModifiedKey ] ) {
+				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+			}
+		}
+
+		// Set the Accepts header for the server, depending on the dataType
+		jqXHR.setRequestHeader(
+			"Accept",
+			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+				s.accepts[ "*" ]
+		);
+
+		// Check for headers option
+		for ( i in s.headers ) {
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
+		}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+				// Abort if not done already and return
+				return jqXHR.abort();
+
+		}
+
+		// aborting is no longer a cancellation
+		strAbort = "abort";
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
+		} else {
+			jqXHR.readyState = 1;
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout( function(){
+					jqXHR.abort( "timeout" );
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch (e) {
+				// Propagate exception as error if not done
+				if ( state < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					throw e;
+				}
+			}
+		}
+
+		return jqXHR;
+	},
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+	var ct, type, finalDataType, firstDataType,
+		contents = s.contents,
+		dataTypes = s.dataTypes,
+		responseFields = s.responseFields;
+
+	// Fill responseXXX fields
+	for ( type in responseFields ) {
+		if ( type in responses ) {
+			jqXHR[ responseFields[type] ] = responses[ type ];
+		}
+	}
+
+	// Remove auto dataType and get content-type in the process
+	while( dataTypes[ 0 ] === "*" ) {
+		dataTypes.shift();
+		if ( ct === undefined ) {
+			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+		}
+	}
+
+	// Check if we're dealing with a known content-type
+	if ( ct ) {
+		for ( type in contents ) {
+			if ( contents[ type ] && contents[ type ].test( ct ) ) {
+				dataTypes.unshift( type );
+				break;
+			}
+		}
+	}
+
+	// Check to see if we have a response for the expected dataType
+	if ( dataTypes[ 0 ] in responses ) {
+		finalDataType = dataTypes[ 0 ];
+	} else {
+		// Try convertible dataTypes
+		for ( type in responses ) {
+			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+				finalDataType = type;
+				break;
+			}
+			if ( !firstDataType ) {
+				firstDataType = type;
+			}
+		}
+		// Or just use first one
+		finalDataType = finalDataType || firstDataType;
+	}
+
+	// If we found a dataType
+	// We add the dataType to the list if needed
+	// and return the corresponding response
+	if ( finalDataType ) {
+		if ( finalDataType !== dataTypes[ 0 ] ) {
+			dataTypes.unshift( finalDataType );
+		}
+		return responses[ finalDataType ];
+	}
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+	var conv, conv2, current, tmp,
+		// Work with a copy of dataTypes in case we need to modify it for conversion
+		dataTypes = s.dataTypes.slice(),
+		prev = dataTypes[ 0 ],
+		converters = {},
+		i = 0;
+
+	// Apply the dataFilter if provided
+	if ( s.dataFilter ) {
+		response = s.dataFilter( response, s.dataType );
+	}
+
+	// Create converters map with lowercased keys
+	if ( dataTypes[ 1 ] ) {
+		for ( conv in s.converters ) {
+			converters[ conv.toLowerCase() ] = s.converters[ conv ];
+		}
+	}
+
+	// Convert to each sequential dataType, tolerating list modification
+	for ( ; (current = dataTypes[++i]); ) {
+
+		// There's only work to do if current dataType is non-auto
+		if ( current !== "*" ) {
+
+			// Convert response if prev dataType is non-auto and differs from current
+			if ( prev !== "*" && prev !== current ) {
+
+				// Seek a direct converter
+				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+				// If none found, seek a pair
+				if ( !conv ) {
+					for ( conv2 in converters ) {
+
+						// If conv2 outputs current
+						tmp = conv2.split(" ");
+						if ( tmp[ 1 ] === current ) {
+
+							// If prev can be converted to accepted input
+							conv = converters[ prev + " " + tmp[ 0 ] ] ||
+								converters[ "* " + tmp[ 0 ] ];
+							if ( conv ) {
+								// Condense equivalence converters
+								if ( conv === true ) {
+									conv = converters[ conv2 ];
+
+								// Otherwise, insert the intermediate dataType
+								} else if ( converters[ conv2 ] !== true ) {
+									current = tmp[ 0 ];
+									dataTypes.splice( i--, 0, current );
+								}
+
+								break;
+							}
+						}
+					}
+				}
+
+				// Apply converter (if not an equivalence)
+				if ( conv !== true ) {
+
+					// Unless errors are allowed to bubble, catch and return them
+					if ( conv && s["throws"] ) {
+						response = conv( response );
+					} else {
+						try {
+							response = conv( response );
+						} catch ( e ) {
+							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+						}
+					}
+				}
+			}
+
+			// Update prev for next iteration
+			prev = current;
+		}
+	}
+
+	return { state: "success", data: response };
+}
+var oldCallbacks = [],
+	rquestion = /\?/,
+	rjsonp = /(=)\?(?=&|$)|\?\?/,
+	nonce = jQuery.now();
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+	jsonp: "callback",
+	jsonpCallback: function() {
+		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+		this[ callback ] = true;
+		return callback;
+	}
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var callbackName, overwritten, responseContainer,
+		data = s.data,
+		url = s.url,
+		hasCallback = s.jsonp !== false,
+		replaceInUrl = hasCallback && rjsonp.test( url ),
+		replaceInData = hasCallback && !replaceInUrl && typeof data === "string" &&
+			!( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") &&
+			rjsonp.test( data );
+
+	// Handle iff the expected data type is "jsonp" or we have a parameter to set
+	if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) {
+
+		// Get callback name, remembering preexisting value associated with it
+		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+			s.jsonpCallback() :
+			s.jsonpCallback;
+		overwritten = window[ callbackName ];
+
+		// Insert callback into url or form data
+		if ( replaceInUrl ) {
+			s.url = url.replace( rjsonp, "$1" + callbackName );
+		} else if ( replaceInData ) {
+			s.data = data.replace( rjsonp, "$1" + callbackName );
+		} else if ( hasCallback ) {
+			s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+		}
+
+		// Use data converter to retrieve json after script execution
+		s.converters["script json"] = function() {
+			if ( !responseContainer ) {
+				jQuery.error( callbackName + " was not called" );
+			}
+			return responseContainer[ 0 ];
+		};
+
+		// force json dataType
+		s.dataTypes[ 0 ] = "json";
+
+		// Install callback
+		window[ callbackName ] = function() {
+			responseContainer = arguments;
+		};
+
+		// Clean-up function (fires after converters)
+		jqXHR.always(function() {
+			// Restore preexisting value
+			window[ callbackName ] = overwritten;
+
+			// Save back as free
+			if ( s[ callbackName ] ) {
+				// make sure that re-using the options doesn't screw things around
+				s.jsonpCallback = originalSettings.jsonpCallback;
+
+				// save the callback name for future use
+				oldCallbacks.push( callbackName );
+			}
+
+			// Call if it was a function and we have a response
+			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+				overwritten( responseContainer[ 0 ] );
+			}
+
+			responseContainer = overwritten = undefined;
+		});
+
+		// Delegate to script
+		return "script";
+	}
+});
+// Install script dataType
+jQuery.ajaxSetup({
+	accepts: {
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+	},
+	contents: {
+		script: /javascript|ecmascript/
+	},
+	converters: {
+		"text script": function( text ) {
+			jQuery.globalEval( text );
+			return text;
+		}
+	}
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+	if ( s.cache === undefined ) {
+		s.cache = false;
+	}
+	if ( s.crossDomain ) {
+		s.type = "GET";
+		s.global = false;
+	}
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+	// This transport only deals with cross domain requests
+	if ( s.crossDomain ) {
+
+		var script,
+			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+		return {
+
+			send: function( _, callback ) {
+
+				script = document.createElement( "script" );
+
+				script.async = "async";
+
+				if ( s.scriptCharset ) {
+					script.charset = s.scriptCharset;
+				}
+
+				script.src = s.url;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+
+						// Remove the script
+						if ( head && script.parentNode ) {
+							head.removeChild( script );
+						}
+
+						// Dereference the script
+						script = undefined;
+
+						// Callback if not abort
+						if ( !isAbort ) {
+							callback( 200, "success" );
+						}
+					}
+				};
+				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+				// This arises when a base node is used (#2709 and #4378).
+				head.insertBefore( script, head.firstChild );
+			},
+
+			abort: function() {
+				if ( script ) {
+					script.onload( 0, 1 );
+				}
+			}
+		};
+	}
+});
+var xhrCallbacks,
+	// #5280: Internet Explorer will keep connections alive if we don't abort on unload
+	xhrOnUnloadAbort = window.ActiveXObject ? function() {
+		// Abort all pending requests
+		for ( var key in xhrCallbacks ) {
+			xhrCallbacks[ key ]( 0, 1 );
+		}
+	} : false,
+	xhrId = 0;
+
+// Functions to create xhrs
+function createStandardXHR() {
+	try {
+		return new window.XMLHttpRequest();
+	} catch( e ) {}
+}
+
+function createActiveXHR() {
+	try {
+		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+	} catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+	/* Microsoft failed to properly
+	 * implement the XMLHttpRequest in IE7 (can't request local files),
+	 * so we use the ActiveXObject when it is available
+	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+	 * we need a fallback.
+	 */
+	function() {
+		return !this.isLocal && createStandardXHR() || createActiveXHR();
+	} :
+	// For all other browsers, use the standard XMLHttpRequest object
+	createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+	jQuery.extend( jQuery.support, {
+		ajax: !!xhr,
+		cors: !!xhr && ( "withCredentials" in xhr )
+	});
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+	jQuery.ajaxTransport(function( s ) {
+		// Cross domain only allowed if supported through XMLHttpRequest
+		if ( !s.crossDomain || jQuery.support.cors ) {
+
+			var callback;
+
+			return {
+				send: function( headers, complete ) {
+
+					// Get a new xhr
+					var handle, i,
+						xhr = s.xhr();
+
+					// Open the socket
+					// Passing null username, generates a login popup on Opera (#2865)
+					if ( s.username ) {
+						xhr.open( s.type, s.url, s.async, s.username, s.password );
+					} else {
+						xhr.open( s.type, s.url, s.async );
+					}
+
+					// Apply custom fields if provided
+					if ( s.xhrFields ) {
+						for ( i in s.xhrFields ) {
+							xhr[ i ] = s.xhrFields[ i ];
+						}
+					}
+
+					// Override mime type if needed
+					if ( s.mimeType && xhr.overrideMimeType ) {
+						xhr.overrideMimeType( s.mimeType );
+					}
+
+					// X-Requested-With header
+					// For cross-domain requests, seeing as conditions for a preflight are
+					// akin to a jigsaw puzzle, we simply never set it to be sure.
+					// (it can always be set on a per-request basis or even using ajaxSetup)
+					// For same-domain requests, won't change header if already provided.
+					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+						headers[ "X-Requested-With" ] = "XMLHttpRequest";
+					}
+
+					// Need an extra try/catch for cross domain requests in Firefox 3
+					try {
+						for ( i in headers ) {
+							xhr.setRequestHeader( i, headers[ i ] );
+						}
+					} catch( _ ) {}
+
+					// Do send the request
+					// This may raise an exception which is actually
+					// handled in jQuery.ajax (so no try/catch here)
+					xhr.send( ( s.hasContent && s.data ) || null );
+
+					// Listener
+					callback = function( _, isAbort ) {
+
+						var status,
+							statusText,
+							responseHeaders,
+							responses,
+							xml;
+
+						// Firefox throws exceptions when accessing properties
+						// of an xhr when a network error occurred
+						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+						try {
+
+							// Was never called and is aborted or complete
+							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+								// Only called once
+								callback = undefined;
+
+								// Do not keep as active anymore
+								if ( handle ) {
+									xhr.onreadystatechange = jQuery.noop;
+									if ( xhrOnUnloadAbort ) {
+										delete xhrCallbacks[ handle ];
+									}
+								}
+
+								// If it's an abort
+								if ( isAbort ) {
+									// Abort it manually if needed
+									if ( xhr.readyState !== 4 ) {
+										xhr.abort();
+									}
+								} else {
+									status = xhr.status;
+									responseHeaders = xhr.getAllResponseHeaders();
+									responses = {};
+									xml = xhr.responseXML;
+
+									// Construct response list
+									if ( xml && xml.documentElement /* #4958 */ ) {
+										responses.xml = xml;
+									}
+
+									// When requesting binary data, IE6-9 will throw an exception
+									// on any attempt to access responseText (#11426)
+									try {
+										responses.text = xhr.responseText;
+									} catch( e ) {
+									}
+
+									// Firefox throws an exception when accessing
+									// statusText for faulty cross-domain requests
+									try {
+										statusText = xhr.statusText;
+									} catch( e ) {
+										// We normalize with Webkit giving an empty statusText
+										statusText = "";
+									}
+
+									// Filter status for non standard behaviors
+
+									// If the request is local and we have data: assume a success
+									// (success with no data won't get notified, that's the best we
+									// can do given current implementations)
+									if ( !status && s.isLocal && !s.crossDomain ) {
+										status = responses.text ? 200 : 404;
+									// IE - #1450: sometimes returns 1223 when it should be 204
+									} else if ( status === 1223 ) {
+										status = 204;
+									}
+								}
+							}
+						} catch( firefoxAccessException ) {
+							if ( !isAbort ) {
+								complete( -1, firefoxAccessException );
+							}
+						}
+
+						// Call complete if needed
+						if ( responses ) {
+							complete( status, statusText, responses, responseHeaders );
+						}
+					};
+
+					if ( !s.async ) {
+						// if we're in sync mode we fire the callback
+						callback();
+					} else if ( xhr.readyState === 4 ) {
+						// (IE6 & IE7) if it's in cache and has been
+						// retrieved directly we need to fire the callback
+						setTimeout( callback, 0 );
+					} else {
+						handle = ++xhrId;
+						if ( xhrOnUnloadAbort ) {
+							// Create the active xhrs callbacks list if needed
+							// and attach the unload handler
+							if ( !xhrCallbacks ) {
+								xhrCallbacks = {};
+								jQuery( window ).unload( xhrOnUnloadAbort );
+							}
+							// Add to list of active xhrs callbacks
+							xhrCallbacks[ handle ] = callback;
+						}
+						xhr.onreadystatechange = callback;
+					}
+				},
+
+				abort: function() {
+					if ( callback ) {
+						callback(0,1);
+					}
+				}
+			};
+		}
+	});
+}
+var fxNow, timerId,
+	rfxtypes = /^(?:toggle|show|hide)$/,
+	rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+	rrun = /queueHooks$/,
+	animationPrefilters = [ defaultPrefilter ],
+	tweeners = {
+		"*": [function( prop, value ) {
+			var end, unit,
+				tween = this.createTween( prop, value ),
+				parts = rfxnum.exec( value ),
+				target = tween.cur(),
+				start = +target || 0,
+				scale = 1,
+				maxIterations = 20;
+
+			if ( parts ) {
+				end = +parts[2];
+				unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+
+				// We need to compute starting value
+				if ( unit !== "px" && start ) {
+					// Iteratively approximate from a nonzero starting point
+					// Prefer the current property, because this process will be trivial if it uses the same units
+					// Fallback to end or a simple constant
+					start = jQuery.css( tween.elem, prop, true ) || end || 1;
+
+					do {
+						// If previous iteration zeroed out, double until we get *something*
+						// Use a string for doubling factor so we don't accidentally see scale as unchanged below
+						scale = scale || ".5";
+
+						// Adjust and apply
+						start = start / scale;
+						jQuery.style( tween.elem, prop, start + unit );
+
+					// Update scale, tolerating zero or NaN from tween.cur()
+					// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+					} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+				}
+
+				tween.unit = unit;
+				tween.start = start;
+				// If a +=/-= token was provided, we're doing a relative animation
+				tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
+			}
+			return tween;
+		}]
+	};
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+	setTimeout(function() {
+		fxNow = undefined;
+	}, 0 );
+	return ( fxNow = jQuery.now() );
+}
+
+function createTweens( animation, props ) {
+	jQuery.each( props, function( prop, value ) {
+		var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+			index = 0,
+			length = collection.length;
+		for ( ; index < length; index++ ) {
+			if ( collection[ index ].call( animation, prop, value ) ) {
+
+				// we're done with this property
+				return;
+			}
+		}
+	});
+}
+
+function Animation( elem, properties, options ) {
+	var result,
+		index = 0,
+		tweenerIndex = 0,
+		length = animationPrefilters.length,
+		deferred = jQuery.Deferred().always( function() {
+			// don't match elem in the :animated selector
+			delete tick.elem;
+		}),
+		tick = function() {
+			var currentTime = fxNow || createFxNow(),
+				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+				temp = remaining / animation.duration || 0,
+				percent = 1 - temp,
+				index = 0,
+				length = animation.tweens.length;
+
+			for ( ; index < length ; index++ ) {
+				animation.tweens[ index ].run( percent );
+			}
+
+			deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+			if ( percent < 1 && length ) {
+				return remaining;
+			} else {
+				deferred.resolveWith( elem, [ animation ] );
+				return false;
+			}
+		},
+		animation = deferred.promise({
+			elem: elem,
+			props: jQuery.extend( {}, properties ),
+			opts: jQuery.extend( true, { specialEasing: {} }, options ),
+			originalProperties: properties,
+			originalOptions: options,
+			startTime: fxNow || createFxNow(),
+			duration: options.duration,
+			tweens: [],
+			createTween: function( prop, end, easing ) {
+				var tween = jQuery.Tween( elem, animation.opts, prop, end,
+						animation.opts.specialEasing[ prop ] || animation.opts.easing );
+				animation.tweens.push( tween );
+				return tween;
+			},
+			stop: function( gotoEnd ) {
+				var index = 0,
+					// if we are going to the end, we want to run all the tweens
+					// otherwise we skip this part
+					length = gotoEnd ? animation.tweens.length : 0;
+
+				for ( ; index < length ; index++ ) {
+					animation.tweens[ index ].run( 1 );
+				}
+
+				// resolve when we played the last frame
+				// otherwise, reject
+				if ( gotoEnd ) {
+					deferred.resolveWith( elem, [ animation, gotoEnd ] );
+				} else {
+					deferred.rejectWith( elem, [ animation, gotoEnd ] );
+				}
+				return this;
+			}
+		}),
+		props = animation.props;
+
+	propFilter( props, animation.opts.specialEasing );
+
+	for ( ; index < length ; index++ ) {
+		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+		if ( result ) {
+			return result;
+		}
+	}
+
+	createTweens( animation, props );
+
+	if ( jQuery.isFunction( animation.opts.start ) ) {
+		animation.opts.start.call( elem, animation );
+	}
+
+	jQuery.fx.timer(
+		jQuery.extend( tick, {
+			anim: animation,
+			queue: animation.opts.queue,
+			elem: elem
+		})
+	);
+
+	// attach callbacks from options
+	return animation.progress( animation.opts.progress )
+		.done( animation.opts.done, animation.opts.complete )
+		.fail( animation.opts.fail )
+		.always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+	var index, name, easing, value, hooks;
+
+	// camelCase, specialEasing and expand cssHook pass
+	for ( index in props ) {
+		name = jQuery.camelCase( index );
+		easing = specialEasing[ name ];
+		value = props[ index ];
+		if ( jQuery.isArray( value ) ) {
+			easing = value[ 1 ];
+			value = props[ index ] = value[ 0 ];
+		}
+
+		if ( index !== name ) {
+			props[ name ] = value;
+			delete props[ index ];
+		}
+
+		hooks = jQuery.cssHooks[ name ];
+		if ( hooks && "expand" in hooks ) {
+			value = hooks.expand( value );
+			delete props[ name ];
+
+			// not quite $.extend, this wont overwrite keys already present.
+			// also - reusing 'index' from above because we have the correct "name"
+			for ( index in value ) {
+				if ( !( index in props ) ) {
+					props[ index ] = value[ index ];
+					specialEasing[ index ] = easing;
+				}
+			}
+		} else {
+			specialEasing[ name ] = easing;
+		}
+	}
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+	tweener: function( props, callback ) {
+		if ( jQuery.isFunction( props ) ) {
+			callback = props;
+			props = [ "*" ];
+		} else {
+			props = props.split(" ");
+		}
+
+		var prop,
+			index = 0,
+			length = props.length;
+
+		for ( ; index < length ; index++ ) {
+			prop = props[ index ];
+			tweeners[ prop ] = tweeners[ prop ] || [];
+			tweeners[ prop ].unshift( callback );
+		}
+	},
+
+	prefilter: function( callback, prepend ) {
+		if ( prepend ) {
+			animationPrefilters.unshift( callback );
+		} else {
+			animationPrefilters.push( callback );
+		}
+	}
+});
+
+function defaultPrefilter( elem, props, opts ) {
+	var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
+		anim = this,
+		style = elem.style,
+		orig = {},
+		handled = [],
+		hidden = elem.nodeType && isHidden( elem );
+
+	// handle queue: false promises
+	if ( !opts.queue ) {
+		hooks = jQuery._queueHooks( elem, "fx" );
+		if ( hooks.unqueued == null ) {
+			hooks.unqueued = 0;
+			oldfire = hooks.empty.fire;
+			hooks.empty.fire = function() {
+				if ( !hooks.unqueued ) {
+					oldfire();
+				}
+			};
+		}
+		hooks.unqueued++;
+
+		anim.always(function() {
+			// doing this makes sure that the complete handler will be called
+			// before this completes
+			anim.always(function() {
+				hooks.unqueued--;
+				if ( !jQuery.queue( elem, "fx" ).length ) {
+					hooks.empty.fire();
+				}
+			});
+		});
+	}
+
+	// height/width overflow pass
+	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+		// Make sure that nothing sneaks out
+		// Record all 3 overflow attributes because IE does not
+		// change the overflow attribute when overflowX and
+		// overflowY are set to the same value
+		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+		// Set display property to inline-block for height/width
+		// animations on inline elements that are having width/height animated
+		if ( jQuery.css( elem, "display" ) === "inline" &&
+				jQuery.css( elem, "float" ) === "none" ) {
+
+			// inline-level elements accept inline-block;
+			// block-level elements need to be inline with layout
+			if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+				style.display = "inline-block";
+
+			} else {
+				style.zoom = 1;
+			}
+		}
+	}
+
+	if ( opts.overflow ) {
+		style.overflow = "hidden";
+		if ( !jQuery.support.shrinkWrapBlocks ) {
+			anim.done(function() {
+				style.overflow = opts.overflow[ 0 ];
+				style.overflowX = opts.overflow[ 1 ];
+				style.overflowY = opts.overflow[ 2 ];
+			});
+		}
+	}
+
+
+	// show/hide pass
+	for ( index in props ) {
+		value = props[ index ];
+		if ( rfxtypes.exec( value ) ) {
+			delete props[ index ];
+			toggle = toggle || value === "toggle";
+			if ( value === ( hidden ? "hide" : "show" ) ) {
+				continue;
+			}
+			handled.push( index );
+		}
+	}
+
+	length = handled.length;
+	if ( length ) {
+		dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
+		if ( "hidden" in dataShow ) {
+			hidden = dataShow.hidden;
+		}
+
+		// store state if its toggle - enables .stop().toggle() to "reverse"
+		if ( toggle ) {
+			dataShow.hidden = !hidden;
+		}
+		if ( hidden ) {
+			jQuery( elem ).show();
+		} else {
+			anim.done(function() {
+				jQuery( elem ).hide();
+			});
+		}
+		anim.done(function() {
+			var prop;
+			jQuery.removeData( elem, "fxshow", true );
+			for ( prop in orig ) {
+				jQuery.style( elem, prop, orig[ prop ] );
+			}
+		});
+		for ( index = 0 ; index < length ; index++ ) {
+			prop = handled[ index ];
+			tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
+			orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
+
+			if ( !( prop in dataShow ) ) {
+				dataShow[ prop ] = tween.start;
+				if ( hidden ) {
+					tween.end = tween.start;
+					tween.start = prop === "width" || prop === "height" ? 1 : 0;
+				}
+			}
+		}
+	}
+}
+
+function Tween( elem, options, prop, end, easing ) {
+	return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+	constructor: Tween,
+	init: function( elem, options, prop, end, easing, unit ) {
+		this.elem = elem;
+		this.prop = prop;
+		this.easing = easing || "swing";
+		this.options = options;
+		this.start = this.now = this.cur();
+		this.end = end;
+		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+	},
+	cur: function() {
+		var hooks = Tween.propHooks[ this.prop ];
+
+		return hooks && hooks.get ?
+			hooks.get( this ) :
+			Tween.propHooks._default.get( this );
+	},
+	run: function( percent ) {
+		var eased,
+			hooks = Tween.propHooks[ this.prop ];
+
+		if ( this.options.duration ) {
+			this.pos = eased = jQuery.easing[ this.easing ](
+				percent, this.options.duration * percent, 0, 1, this.options.duration
+			);
+		} else {
+			this.pos = eased = percent;
+		}
+		this.now = ( this.end - this.start ) * eased + this.start;
+
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		if ( hooks && hooks.set ) {
+			hooks.set( this );
+		} else {
+			Tween.propHooks._default.set( this );
+		}
+		return this;
+	}
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+	_default: {
+		get: function( tween ) {
+			var result;
+
+			if ( tween.elem[ tween.prop ] != null &&
+				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+				return tween.elem[ tween.prop ];
+			}
+
+			// passing any value as a 4th parameter to .css will automatically
+			// attempt a parseFloat and fallback to a string if the parse fails
+			// so, simple values such as "10px" are parsed to Float.
+			// complex values such as "rotate(1rad)" are returned as is.
+			result = jQuery.css( tween.elem, tween.prop, false, "" );
+			// Empty strings, null, undefined and "auto" are converted to 0.
+			return !result || result === "auto" ? 0 : result;
+		},
+		set: function( tween ) {
+			// use step hook for back compat - use cssHook if its there - use .style if its
+			// available and use plain properties where available
+			if ( jQuery.fx.step[ tween.prop ] ) {
+				jQuery.fx.step[ tween.prop ]( tween );
+			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+			} else {
+				tween.elem[ tween.prop ] = tween.now;
+			}
+		}
+	}
+};
+
+// Remove in 2.0 - this supports IE8's panic based approach
+// to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+	set: function( tween ) {
+		if ( tween.elem.nodeType && tween.elem.parentNode ) {
+			tween.elem[ tween.prop ] = tween.now;
+		}
+	}
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+	var cssFn = jQuery.fn[ name ];
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return speed == null || typeof speed === "boolean" ||
+			// special check for .toggle( handler, handler, ... )
+			( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ?
+			cssFn.apply( this, arguments ) :
+			this.animate( genFx( name, true ), speed, easing, callback );
+	};
+});
+
+jQuery.fn.extend({
+	fadeTo: function( speed, to, easing, callback ) {
+
+		// show any hidden elements after setting opacity to 0
+		return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+			// animate to the value specified
+			.end().animate({ opacity: to }, speed, easing, callback );
+	},
+	animate: function( prop, speed, easing, callback ) {
+		var empty = jQuery.isEmptyObject( prop ),
+			optall = jQuery.speed( speed, easing, callback ),
+			doAnimation = function() {
+				// Operate on a copy of prop so per-property easing won't be lost
+				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+				// Empty animations resolve immediately
+				if ( empty ) {
+					anim.stop( true );
+				}
+			};
+
+		return empty || optall.queue === false ?
+			this.each( doAnimation ) :
+			this.queue( optall.queue, doAnimation );
+	},
+	stop: function( type, clearQueue, gotoEnd ) {
+		var stopQueue = function( hooks ) {
+			var stop = hooks.stop;
+			delete hooks.stop;
+			stop( gotoEnd );
+		};
+
+		if ( typeof type !== "string" ) {
+			gotoEnd = clearQueue;
+			clearQueue = type;
+			type = undefined;
+		}
+		if ( clearQueue && type !== false ) {
+			this.queue( type || "fx", [] );
+		}
+
+		return this.each(function() {
+			var dequeue = true,
+				index = type != null && type + "queueHooks",
+				timers = jQuery.timers,
+				data = jQuery._data( this );
+
+			if ( index ) {
+				if ( data[ index ] && data[ index ].stop ) {
+					stopQueue( data[ index ] );
+				}
+			} else {
+				for ( index in data ) {
+					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+						stopQueue( data[ index ] );
+					}
+				}
+			}
+
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+					timers[ index ].anim.stop( gotoEnd );
+					dequeue = false;
+					timers.splice( index, 1 );
+				}
+			}
+
+			// start the next in the queue if the last step wasn't forced
+			// timers currently will call their complete callbacks, which will dequeue
+			// but only if they were gotoEnd
+			if ( dequeue || !gotoEnd ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	}
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+	var which,
+		attrs = { height: type },
+		i = 0;
+
+	// if we include width, step value is 1 to do all cssExpand values,
+	// if we don't include width, step value is 2 to skip over Left and Right
+	includeWidth = includeWidth? 1 : 0;
+	for( ; i < 4 ; i += 2 - includeWidth ) {
+		which = cssExpand[ i ];
+		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+	}
+
+	if ( includeWidth ) {
+		attrs.opacity = attrs.width = type;
+	}
+
+	return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show"),
+	slideUp: genFx("hide"),
+	slideToggle: genFx("toggle"),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" },
+	fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return this.animate( props, speed, easing, callback );
+	};
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+		complete: fn || !fn && easing ||
+			jQuery.isFunction( speed ) && speed,
+		duration: speed,
+		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+	};
+
+	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+	// normalize opt.queue - true/undefined/null -> "fx"
+	if ( opt.queue == null || opt.queue === true ) {
+		opt.queue = "fx";
+	}
+
+	// Queueing
+	opt.old = opt.complete;
+
+	opt.complete = function() {
+		if ( jQuery.isFunction( opt.old ) ) {
+			opt.old.call( this );
+		}
+
+		if ( opt.queue ) {
+			jQuery.dequeue( this, opt.queue );
+		}
+	};
+
+	return opt;
+};
+
+jQuery.easing = {
+	linear: function( p ) {
+		return p;
+	},
+	swing: function( p ) {
+		return 0.5 - Math.cos( p*Math.PI ) / 2;
+	}
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+	var timer,
+		timers = jQuery.timers,
+		i = 0;
+
+	fxNow = jQuery.now();
+
+	for ( ; i < timers.length; i++ ) {
+		timer = timers[ i ];
+		// Checks the timer has not already been removed
+		if ( !timer() && timers[ i ] === timer ) {
+			timers.splice( i--, 1 );
+		}
+	}
+
+	if ( !timers.length ) {
+		jQuery.fx.stop();
+	}
+	fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+	if ( timer() && jQuery.timers.push( timer ) && !timerId ) {
+		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+	}
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.stop = function() {
+	clearInterval( timerId );
+	timerId = null;
+};
+
+jQuery.fx.speeds = {
+	slow: 600,
+	fast: 200,
+	// Default speed
+	_default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.animated = function( elem ) {
+		return jQuery.grep(jQuery.timers, function( fn ) {
+			return elem === fn.elem;
+		}).length;
+	};
+}
+var rroot = /^(?:body|html)$/i;
+
+jQuery.fn.offset = function( options ) {
+	if ( arguments.length ) {
+		return options === undefined ?
+			this :
+			this.each(function( i ) {
+				jQuery.offset.setOffset( this, options, i );
+			});
+	}
+
+	var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft,
+		box = { top: 0, left: 0 },
+		elem = this[ 0 ],
+		doc = elem && elem.ownerDocument;
+
+	if ( !doc ) {
+		return;
+	}
+
+	if ( (body = doc.body) === elem ) {
+		return jQuery.offset.bodyOffset( elem );
+	}
+
+	docElem = doc.documentElement;
+
+	// Make sure it's not a disconnected DOM node
+	if ( !jQuery.contains( docElem, elem ) ) {
+		return box;
+	}
+
+	// If we don't have gBCR, just use 0,0 rather than error
+	// BlackBerry 5, iOS 3 (original iPhone)
+	if ( typeof elem.getBoundingClientRect !== "undefined" ) {
+		box = elem.getBoundingClientRect();
+	}
+	win = getWindow( doc );
+	clientTop  = docElem.clientTop  || body.clientTop  || 0;
+	clientLeft = docElem.clientLeft || body.clientLeft || 0;
+	scrollTop  = win.pageYOffset || docElem.scrollTop;
+	scrollLeft = win.pageXOffset || docElem.scrollLeft;
+	return {
+		top: box.top  + scrollTop  - clientTop,
+		left: box.left + scrollLeft - clientLeft
+	};
+};
+
+jQuery.offset = {
+
+	bodyOffset: function( body ) {
+		var top = body.offsetTop,
+			left = body.offsetLeft;
+
+		if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+		}
+
+		return { top: top, left: left };
+	},
+
+	setOffset: function( elem, options, i ) {
+		var position = jQuery.css( elem, "position" );
+
+		// set position first, in-case top/left are set even on static elem
+		if ( position === "static" ) {
+			elem.style.position = "relative";
+		}
+
+		var curElem = jQuery( elem ),
+			curOffset = curElem.offset(),
+			curCSSTop = jQuery.css( elem, "top" ),
+			curCSSLeft = jQuery.css( elem, "left" ),
+			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+			props = {}, curPosition = {}, curTop, curLeft;
+
+		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+		if ( calculatePosition ) {
+			curPosition = curElem.position();
+			curTop = curPosition.top;
+			curLeft = curPosition.left;
+		} else {
+			curTop = parseFloat( curCSSTop ) || 0;
+			curLeft = parseFloat( curCSSLeft ) || 0;
+		}
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		if ( options.top != null ) {
+			props.top = ( options.top - curOffset.top ) + curTop;
+		}
+		if ( options.left != null ) {
+			props.left = ( options.left - curOffset.left ) + curLeft;
+		}
+
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+
+jQuery.fn.extend({
+
+	position: function() {
+		if ( !this[0] ) {
+			return;
+		}
+
+		var elem = this[0],
+
+		// Get *real* offsetParent
+		offsetParent = this.offsetParent(),
+
+		// Get correct offsets
+		offset       = this.offset(),
+		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+		// Subtract element margins
+		// note: when an element has margin: auto the offsetLeft and marginLeft
+		// are the same in Safari causing offset.left to incorrectly be 0
+		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+		// Add offsetParent borders
+		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+		// Subtract the two offsets
+		return {
+			top:  offset.top  - parentOffset.top,
+			left: offset.left - parentOffset.left
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || document.body;
+			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+			return offsetParent || document.body;
+		});
+	}
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+	var top = /Y/.test( prop );
+
+	jQuery.fn[ method ] = function( val ) {
+		return jQuery.access( this, function( elem, method, val ) {
+			var win = getWindow( elem );
+
+			if ( val === undefined ) {
+				return win ? (prop in win) ? win[ prop ] :
+					win.document.documentElement[ method ] :
+					elem[ method ];
+			}
+
+			if ( win ) {
+				win.scrollTo(
+					!top ? val : jQuery( win ).scrollLeft(),
+					 top ? val : jQuery( win ).scrollTop()
+				);
+
+			} else {
+				elem[ method ] = val;
+			}
+		}, method, val, arguments.length, null );
+	};
+});
+
+function getWindow( elem ) {
+	return jQuery.isWindow( elem ) ?
+		elem :
+		elem.nodeType === 9 ?
+			elem.defaultView || elem.parentWindow :
+			false;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+		// margin is only for outerHeight, outerWidth
+		jQuery.fn[ funcName ] = function( margin, value ) {
+			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+			return jQuery.access( this, function( elem, type, value ) {
+				var doc;
+
+				if ( jQuery.isWindow( elem ) ) {
+					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+					// isn't a whole lot we can do. See pull request at this URL for discussion:
+					// https://github.com/jquery/jquery/pull/764
+					return elem.document.documentElement[ "client" + name ];
+				}
+
+				// Get document width or height
+				if ( elem.nodeType === 9 ) {
+					doc = elem.documentElement;
+
+					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+					// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+					return Math.max(
+						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+						elem.body[ "offset" + name ], doc[ "offset" + name ],
+						doc[ "client" + name ]
+					);
+				}
+
+				return value === undefined ?
+					// Get width or height on the element, requesting but not forcing parseFloat
+					jQuery.css( elem, type, value, extra ) :
+
+					// Set width or height on the element
+					jQuery.style( elem, type, value, extra );
+			}, type, chainable ? margin : undefined, chainable, null );
+		};
+	});
+});
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+	define( "jquery", [], function () { return jQuery; } );
+}
+
+})( window );
+//     Underscore.js 1.8.2
+//     http://underscorejs.org
+//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Underscore may be freely distributed under the MIT license.
+
+(function() {
+
+    // Baseline setup
+    // --------------
+
+    // Establish the root object, `window` in the browser, or `exports` on the server.
+    var root = this;
+
+    // Save the previous value of the `_` variable.
+    var previousUnderscore = root._;
+
+    // Save bytes in the minified (but not gzipped) version:
+    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
+
+    // Create quick reference variables for speed access to core prototypes.
+    var
+        push             = ArrayProto.push,
+        slice            = ArrayProto.slice,
+        toString         = ObjProto.toString,
+        hasOwnProperty   = ObjProto.hasOwnProperty;
+
+    // All **ECMAScript 5** native function implementations that we hope to use
+    // are declared here.
+    var
+        nativeIsArray      = Array.isArray,
+        nativeKeys         = Object.keys,
+        nativeBind         = FuncProto.bind,
+        nativeCreate       = Object.create;
+
+    // Naked function reference for surrogate-prototype-swapping.
+    var Ctor = function(){};
+
+    // Create a safe reference to the Underscore object for use below.
+    var _ = function(obj) {
+        if (obj instanceof _) return obj;
+        if (!(this instanceof _)) return new _(obj);
+        this._wrapped = obj;
+    };
+
+    // Export the Underscore object for **Node.js**, with
+    // backwards-compatibility for the old `require()` API. If we're in
+    // the browser, add `_` as a global object.
+    if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports) {
+            exports = module.exports = _;
+        }
+        exports._ = _;
+    } else {
+        root._ = _;
+    }
+
+    // Current version.
+    _.VERSION = '1.8.2';
+
+    // Internal function that returns an efficient (for current engines) version
+    // of the passed-in callback, to be repeatedly applied in other Underscore
+    // functions.
+    var optimizeCb = function(func, context, argCount) {
+        if (context === void 0) return func;
+        switch (argCount == null ? 3 : argCount) {
+            case 1: return function(value) {
+                return func.call(context, value);
+            };
+            case 2: return function(value, other) {
+                return func.call(context, value, other);
+            };
+            case 3: return function(value, index, collection) {
+                return func.call(context, value, index, collection);
+            };
+            case 4: return function(accumulator, value, index, collection) {
+                return func.call(context, accumulator, value, index, collection);
+            };
+        }
+        return function() {
+            return func.apply(context, arguments);
+        };
+    };
+
+    // A mostly-internal function to generate callbacks that can be applied
+    // to each element in a collection, returning the desired result 鈥? either
+    // identity, an arbitrary callback, a property matcher, or a property accessor.
+    var cb = function(value, context, argCount) {
+        if (value == null) return _.identity;
+        if (_.isFunction(value)) return optimizeCb(value, context, argCount);
+        if (_.isObject(value)) return _.matcher(value);
+        return _.property(value);
+    };
+    _.iteratee = function(value, context) {
+        return cb(value, context, Infinity);
+    };
+
+    // An internal function for creating assigner functions.
+    var createAssigner = function(keysFunc, undefinedOnly) {
+        return function(obj) {
+            var length = arguments.length;
+            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 (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
+                }
+            }
+            return obj;
+        };
+    };
+
+    // An internal function for creating a new object that inherits from another.
+    var baseCreate = function(prototype) {
+        if (!_.isObject(prototype)) return {};
+        if (nativeCreate) return nativeCreate(prototype);
+        Ctor.prototype = prototype;
+        var result = new Ctor;
+        Ctor.prototype = null;
+        return result;
+    };
+
+    // Helper for collection methods to determine whether a collection
+    // should be iterated as an array or as an object
+    // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
+    var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
+    var isArrayLike = function(collection) {
+        var length = collection != null && collection.length;
+        return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
+    };
+
+    // Collection Functions
+    // --------------------
+
+    // The cornerstone, an `each` implementation, aka `forEach`.
+    // Handles raw objects in addition to array-likes. Treats all
+    // sparse array-likes as if they were dense.
+    _.each = _.forEach = function(obj, iteratee, context) {
+        iteratee = optimizeCb(iteratee, context);
+        var i, length;
+        if (isArrayLike(obj)) {
+            for (i = 0, length = obj.length; i < length; i++) {
+                iteratee(obj[i], i, obj);
+            }
+        } else {
+            var keys = _.keys(obj);
+            for (i = 0, length = keys.length; i < length; i++) {
+                iteratee(obj[keys[i]], keys[i], obj);
+            }
+        }
+        return obj;
+    };
+
+    // Return the results of applying the iteratee to each element.
+    _.map = _.collect = function(obj, iteratee, context) {
+        iteratee = cb(iteratee, context);
+        var keys = !isArrayLike(obj) && _.keys(obj),
+            length = (keys || obj).length,
+            results = Array(length);
+        for (var index = 0; index < length; index++) {
+            var currentKey = keys ? keys[index] : index;
+            results[index] = iteratee(obj[currentKey], currentKey, obj);
+        }
+        return results;
+    };
+
+    // Create a reducing function iterating left or right.
+    function createReduce(dir) {
+        // Optimized iterator function as using arguments.length
+        // in the main function will deoptimize the, see #1991.
+        function iterator(obj, iteratee, memo, keys, index, length) {
+            for (; index >= 0 && index < length; index += dir) {
+                var currentKey = keys ? keys[index] : index;
+                memo = iteratee(memo, obj[currentKey], currentKey, obj);
+            }
+            return memo;
+        }
+
+        return function(obj, iteratee, memo, context) {
+            iteratee = optimizeCb(iteratee, context, 4);
+            var keys = !isArrayLike(obj) && _.keys(obj),
+                length = (keys || obj).length,
+                index = dir > 0 ? 0 : length - 1;
+            // Determine the initial value if none is provided.
+            if (arguments.length < 3) {
+                memo = obj[keys ? keys[index] : index];
+                index += dir;
+            }
+            return iterator(obj, iteratee, memo, keys, index, length);
+        };
+    }
+
+    // **Reduce** builds up a single result from a list of values, aka `inject`,
+    // or `foldl`.
+    _.reduce = _.foldl = _.inject = createReduce(1);
+
+    // The right-associative version of reduce, also known as `foldr`.
+    _.reduceRight = _.foldr = createReduce(-1);
+
+    // Return the first value which passes a truth test. Aliased as `detect`.
+    _.find = _.detect = function(obj, predicate, context) {
+        var key;
+        if (isArrayLike(obj)) {
+            key = _.findIndex(obj, predicate, context);
+        } else {
+            key = _.findKey(obj, predicate, context);
+        }
+        if (key !== void 0 && key !== -1) return obj[key];
+    };
+
+    // Return all the elements that pass a truth test.
+    // Aliased as `select`.
+    _.filter = _.select = function(obj, predicate, context) {
+        var results = [];
+        predicate = cb(predicate, context);
+        _.each(obj, function(value, index, list) {
+            if (predicate(value, index, list)) results.push(value);
+        });
+        return results;
+    };
+
+    // Return all the elements for which a truth test fails.
+    _.reject = function(obj, predicate, context) {
+        return _.filter(obj, _.negate(cb(predicate)), context);
+    };
+
+    // Determine whether all of the elements match a truth test.
+    // Aliased as `all`.
+    _.every = _.all = function(obj, predicate, context) {
+        predicate = cb(predicate, context);
+        var keys = !isArrayLike(obj) && _.keys(obj),
+            length = (keys || obj).length;
+        for (var index = 0; index < length; index++) {
+            var currentKey = keys ? keys[index] : index;
+            if (!predicate(obj[currentKey], currentKey, obj)) return false;
+        }
+        return true;
+    };
+
+    // Determine if at least one element in the object matches a truth test.
+    // Aliased as `any`.
+    _.some = _.any = function(obj, predicate, context) {
+        predicate = cb(predicate, context);
+        var keys = !isArrayLike(obj) && _.keys(obj),
+            length = (keys || obj).length;
+        for (var index = 0; index < length; index++) {
+            var currentKey = keys ? keys[index] : index;
+            if (predicate(obj[currentKey], currentKey, obj)) return true;
+        }
+        return false;
+    };
+
+    // Determine if the array or object contains a given value (using `===`).
+    // Aliased as `includes` and `include`.
+    _.contains = _.includes = _.include = function(obj, target, fromIndex) {
+        if (!isArrayLike(obj)) obj = _.values(obj);
+        return _.indexOf(obj, target, typeof fromIndex == 'number' && fromIndex) >= 0;
+    };
+
+    // Invoke a method (with arguments) on every item in a collection.
+    _.invoke = function(obj, method) {
+        var args = slice.call(arguments, 2);
+        var isFunc = _.isFunction(method);
+        return _.map(obj, function(value) {
+            var func = isFunc ? method : value[method];
+            return func == null ? func : func.apply(value, args);
+        });
+    };
+
+    // Convenience version of a common use case of `map`: fetching a property.
+    _.pluck = function(obj, key) {
+        return _.map(obj, _.property(key));
+    };
+
+    // Convenience version of a common use case of `filter`: selecting only objects
+    // containing specific `key:value` pairs.
+    _.where = function(obj, attrs) {
+        return _.filter(obj, _.matcher(attrs));
+    };
+
+    // Convenience version of a common use case of `find`: getting the first object
+    // containing specific `key:value` pairs.
+    _.findWhere = function(obj, attrs) {
+        return _.find(obj, _.matcher(attrs));
+    };
+
+    // Return the maximum element (or element-based computation).
+    _.max = function(obj, iteratee, context) {
+        var result = -Infinity, lastComputed = -Infinity,
+            value, computed;
+        if (iteratee == null && obj != null) {
+            obj = isArrayLike(obj) ? obj : _.values(obj);
+            for (var i = 0, length = obj.length; i < length; i++) {
+                value = obj[i];
+                if (value > result) {
+                    result = value;
+                }
+            }
+        } else {
+            iteratee = cb(iteratee, context);
+            _.each(obj, function(value, index, list) {
+                computed = iteratee(value, index, list);
+                if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+                    result = value;
+                    lastComputed = computed;
+                }
+            });
+        }
+        return result;
+    };
+
+    // Return the minimum element (or element-based computation).
+    _.min = function(obj, iteratee, context) {
+        var result = Infinity, lastComputed = Infinity,
+            value, computed;
+        if (iteratee == null && obj != null) {
+            obj = isArrayLike(obj) ? obj : _.values(obj);
+            for (var i = 0, length = obj.length; i < length; i++) {
+                value = obj[i];
+                if (value < result) {
+                    result = value;
+                }
+            }
+        } else {
+            iteratee = cb(iteratee, context);
+            _.each(obj, function(value, index, list) {
+                computed = iteratee(value, index, list);
+                if (computed < lastComputed || computed === Infinity && result === Infinity) {
+                    result = value;
+                    lastComputed = computed;
+                }
+            });
+        }
+        return result;
+    };
+
+    // Shuffle a collection, using the modern version of the
+    // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher鈥揧ates_shuffle).
+    _.shuffle = function(obj) {
+        var set = isArrayLike(obj) ? obj : _.values(obj);
+        var length = set.length;
+        var shuffled = Array(length);
+        for (var index = 0, rand; index < length; index++) {
+            rand = _.random(0, index);
+            if (rand !== index) shuffled[index] = shuffled[rand];
+            shuffled[rand] = set[index];
+        }
+        return shuffled;
+    };
+
+    // Sample **n** random values from a collection.
+    // If **n** is not specified, returns a single random element.
+    // The internal `guard` argument allows it to work with `map`.
+    _.sample = function(obj, n, guard) {
+        if (n == null || guard) {
+            if (!isArrayLike(obj)) obj = _.values(obj);
+            return obj[_.random(obj.length - 1)];
+        }
+        return _.shuffle(obj).slice(0, Math.max(0, n));
+    };
+
+    // Sort the object's values by a criterion produced by an iteratee.
+    _.sortBy = function(obj, iteratee, context) {
+        iteratee = cb(iteratee, context);
+        return _.pluck(_.map(obj, function(value, index, list) {
+            return {
+                value: value,
+                index: index,
+                criteria: iteratee(value, index, list)
+            };
+        }).sort(function(left, right) {
+            var a = left.criteria;
+            var b = right.criteria;
+            if (a !== b) {
+                if (a > b || a === void 0) return 1;
+                if (a < b || b === void 0) return -1;
+            }
+            return left.index - right.index;
+        }), 'value');
+    };
+
+    // An internal function used for aggregate "group by" operations.
+    var group = function(behavior) {
+        return function(obj, iteratee, context) {
+            var result = {};
+            iteratee = cb(iteratee, context);
+            _.each(obj, function(value, index) {
+                var key = iteratee(value, index, obj);
+                behavior(result, value, key);
+            });
+            return result;
+        };
+    };
+
+    // Groups the object's values by a criterion. Pass either a string attribute
+    // to group by, or a function that returns the criterion.
+    _.groupBy = group(function(result, value, key) {
+        if (_.has(result, key)) result[key].push(value); else result[key] = [value];
+    });
+
+    // Indexes the object's values by a criterion, similar to `groupBy`, but for
+    // when you know that your index values will be unique.
+    _.indexBy = group(function(result, value, key) {
+        result[key] = value;
+    });
+
+    // Counts instances of an object that group by a certain criterion. Pass
+    // either a string attribute to count by, or a function that returns the
+    // criterion.
+    _.countBy = group(function(result, value, key) {
+        if (_.has(result, key)) result[key]++; else result[key] = 1;
+    });
+
+    // Safely create a real, live array from anything iterable.
+    _.toArray = function(obj) {
+        if (!obj) return [];
+        if (_.isArray(obj)) return slice.call(obj);
+        if (isArrayLike(obj)) return _.map(obj, _.identity);
+        return _.values(obj);
+    };
+
+    // Return the number of elements in an object.
+    _.size = function(obj) {
+        if (obj == null) return 0;
+        return isArrayLike(obj) ? obj.length : _.keys(obj).length;
+    };
+
+    // Split a collection into two arrays: one whose elements all satisfy the given
+    // predicate, and one whose elements all do not satisfy the predicate.
+    _.partition = function(obj, predicate, context) {
+        predicate = cb(predicate, context);
+        var pass = [], fail = [];
+        _.each(obj, function(value, key, obj) {
+            (predicate(value, key, obj) ? pass : fail).push(value);
+        });
+        return [pass, fail];
+    };
+
+    // Array Functions
+    // ---------------
+
+    // Get the first element of an array. Passing **n** will return the first N
+    // values in the array. Aliased as `head` and `take`. The **guard** check
+    // allows it to work with `_.map`.
+    _.first = _.head = _.take = function(array, n, guard) {
+        if (array == null) return void 0;
+        if (n == null || guard) return array[0];
+        return _.initial(array, array.length - n);
+    };
+
+    // Returns everything but the last entry of the array. Especially useful on
+    // the arguments object. Passing **n** will return all the values in
+    // the array, excluding the last N.
+    _.initial = function(array, n, guard) {
+        return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+    };
+
+    // Get the last element of an array. Passing **n** will return the last N
+    // values in the array.
+    _.last = function(array, n, guard) {
+        if (array == null) return void 0;
+        if (n == null || guard) return array[array.length - 1];
+        return _.rest(array, Math.max(0, array.length - n));
+    };
+
+    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+    // Especially useful on the arguments object. Passing an **n** will return
+    // the rest N values in the array.
+    _.rest = _.tail = _.drop = function(array, n, guard) {
+        return slice.call(array, n == null || guard ? 1 : n);
+    };
+
+    // Trim out all falsy values from an array.
+    _.compact = function(array) {
+        return _.filter(array, _.identity);
+    };
+
+    // Internal implementation of a recursive `flatten` function.
+    var flatten = function(input, shallow, strict, startIndex) {
+        var output = [], idx = 0;
+        for (var i = startIndex || 0, length = input && input.length; i < length; i++) {
+            var value = input[i];
+            if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
+                //flatten current level of array or arguments object
+                if (!shallow) value = flatten(value, shallow, strict);
+                var j = 0, len = value.length;
+                output.length += len;
+                while (j < len) {
+                    output[idx++] = value[j++];
+                }
+            } else if (!strict) {
+                output[idx++] = value;
+            }
+        }
+        return output;
+    };
+
+    // Flatten out an array, either recursively (by default), or just one level.
+    _.flatten = function(array, shallow) {
+        return flatten(array, shallow, false);
+    };
+
+    // Return a version of the array that does not contain the specified value(s).
+    _.without = function(array) {
+        return _.difference(array, slice.call(arguments, 1));
+    };
+
+    // Produce a duplicate-free version of the array. If the array has already
+    // been sorted, you have the option of using a faster algorithm.
+    // Aliased as `unique`.
+    _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+        if (array == null) return [];
+        if (!_.isBoolean(isSorted)) {
+            context = iteratee;
+            iteratee = isSorted;
+            isSorted = false;
+        }
+        if (iteratee != null) iteratee = cb(iteratee, context);
+        var result = [];
+        var seen = [];
+        for (var i = 0, length = array.length; i < length; i++) {
+            var value = array[i],
+                computed = iteratee ? iteratee(value, i, array) : value;
+            if (isSorted) {
+                if (!i || seen !== computed) result.push(value);
+                seen = computed;
+            } else if (iteratee) {
+                if (!_.contains(seen, computed)) {
+                    seen.push(computed);
+                    result.push(value);
+                }
+            } else if (!_.contains(result, value)) {
+                result.push(value);
+            }
+        }
+        return result;
+    };
+
+    // Produce an array that contains the union: each distinct element from all of
+    // the passed-in arrays.
+    _.union = function() {
+        return _.uniq(flatten(arguments, true, true));
+    };
+
+    // Produce an array that contains every item shared between all the
+    // passed-in arrays.
+    _.intersection = function(array) {
+        if (array == null) return [];
+        var result = [];
+        var argsLength = arguments.length;
+        for (var i = 0, length = array.length; i < length; i++) {
+            var item = array[i];
+            if (_.contains(result, item)) continue;
+            for (var j = 1; j < argsLength; j++) {
+                if (!_.contains(arguments[j], item)) break;
+            }
+            if (j === argsLength) result.push(item);
+        }
+        return result;
+    };
+
+    // Take the difference between one array and a number of other arrays.
+    // Only the elements present in just the first array will remain.
+    _.difference = function(array) {
+        var rest = flatten(arguments, true, true, 1);
+        return _.filter(array, function(value){
+            return !_.contains(rest, value);
+        });
+    };
+
+    // Zip together multiple lists into a single array -- elements that share
+    // an index go together.
+    _.zip = function() {
+        return _.unzip(arguments);
+    };
+
+    // Complement of _.zip. Unzip accepts an array of arrays and groups
+    // each array's elements on shared indices
+    _.unzip = function(array) {
+        var length = array && _.max(array, 'length').length || 0;
+        var result = Array(length);
+
+        for (var index = 0; index < length; index++) {
+            result[index] = _.pluck(array, index);
+        }
+        return result;
+    };
+
+    // Converts lists into objects. Pass either a single array of `[key, value]`
+    // pairs, or two parallel arrays of the same length -- one of keys, and one of
+    // the corresponding values.
+    _.object = function(list, values) {
+        var result = {};
+        for (var i = 0, length = list && list.length; i < length; i++) {
+            if (values) {
+                result[list[i]] = values[i];
+            } else {
+                result[list[i][0]] = list[i][1];
+            }
+        }
+        return result;
+    };
+
+    // Return the position of the first occurrence of an item in an array,
+    // or -1 if the item is not included in the array.
+    // If the array is large and already in sort order, pass `true`
+    // for **isSorted** to use binary search.
+    _.indexOf = function(array, item, isSorted) {
+        var i = 0, length = array && array.length;
+        if (typeof isSorted == 'number') {
+            i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
+        } else if (isSorted && length) {
+            i = _.sortedIndex(array, item);
+            return array[i] === item ? i : -1;
+        }
+        if (item !== item) {
+            return _.findIndex(slice.call(array, i), _.isNaN);
+        }
+        for (; i < length; i++) if (array[i] === item) return i;
+        return -1;
+    };
+
+    _.lastIndexOf = function(array, item, from) {
+        var idx = array ? array.length : 0;
+        if (typeof from == 'number') {
+            idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
+        }
+        if (item !== item) {
+            return _.findLastIndex(slice.call(array, 0, idx), _.isNaN);
+        }
+        while (--idx >= 0) if (array[idx] === item) return idx;
+        return -1;
+    };
+
+    // Generator function to create the findIndex and findLastIndex functions
+    function createIndexFinder(dir) {
+        return function(array, predicate, context) {
+            predicate = cb(predicate, context);
+            var length = array != null && array.length;
+            var index = dir > 0 ? 0 : length - 1;
+            for (; index >= 0 && index < length; index += dir) {
+                if (predicate(array[index], index, array)) return index;
+            }
+            return -1;
+        };
+    }
+
+    // Returns the first index on an array-like that passes a predicate test
+    _.findIndex = createIndexFinder(1);
+
+    _.findLastIndex = createIndexFinder(-1);
+
+    // Use a comparator function to figure out the smallest index at which
+    // an object should be inserted so as to maintain order. Uses binary search.
+    _.sortedIndex = function(array, obj, iteratee, context) {
+        iteratee = cb(iteratee, context, 1);
+        var value = iteratee(obj);
+        var low = 0, high = array.length;
+        while (low < high) {
+            var mid = Math.floor((low + high) / 2);
+            if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
+        }
+        return low;
+    };
+
+    // Generate an integer Array containing an arithmetic progression. A port of
+    // the native Python `range()` function. See
+    // [the Python documentation](http://docs.python.org/library/functions.html#range).
+    _.range = function(start, stop, step) {
+        if (arguments.length <= 1) {
+            stop = start || 0;
+            start = 0;
+        }
+        step = step || 1;
+
+        var length = Math.max(Math.ceil((stop - start) / step), 0);
+        var range = Array(length);
+
+        for (var idx = 0; idx < length; idx++, start += step) {
+            range[idx] = start;
+        }
+
+        return range;
+    };
+
+    // Function (ahem) Functions
+    // ------------------
+
+    // Determines whether to execute a function as a constructor
+    // or a normal function with the provided arguments
+    var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
+        if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+        var self = baseCreate(sourceFunc.prototype);
+        var result = sourceFunc.apply(self, args);
+        if (_.isObject(result)) return result;
+        return self;
+    };
+
+    // Create a function bound to a given object (assigning `this`, and arguments,
+    // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+    // available.
+    _.bind = function(func, context) {
+        if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+        if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+        var args = slice.call(arguments, 2);
+        var bound = function() {
+            return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
+        };
+        return bound;
+    };
+
+    // Partially apply a function by creating a version that has had some of its
+    // arguments pre-filled, without changing its dynamic `this` context. _ acts
+    // as a placeholder, allowing any combination of arguments to be pre-filled.
+    _.partial = function(func) {
+        var boundArgs = slice.call(arguments, 1);
+        var bound = function() {
+            var position = 0, length = boundArgs.length;
+            var args = Array(length);
+            for (var i = 0; i < length; i++) {
+                args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
+            }
+            while (position < arguments.length) args.push(arguments[position++]);
+            return executeBound(func, bound, this, this, args);
+        };
+        return bound;
+    };
+
+    // Bind a number of an object's methods to that object. Remaining arguments
+    // are the method names to be bound. Useful for ensuring that all callbacks
+    // defined on an object belong to it.
+    _.bindAll = function(obj) {
+        var i, length = arguments.length, key;
+        if (length <= 1) throw new Error('bindAll must be passed function names');
+        for (i = 1; i < length; i++) {
+            key = arguments[i];
+            obj[key] = _.bind(obj[key], obj);
+        }
+        return obj;
+    };
+
+    // Memoize an expensive function by storing its results.
+    _.memoize = function(func, hasher) {
+        var memoize = function(key) {
+            var cache = memoize.cache;
+            var address = '' + (hasher ? hasher.apply(this, arguments) : key);
+            if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+            return cache[address];
+        };
+        memoize.cache = {};
+        return memoize;
+    };
+
+    // Delays a function for the given number of milliseconds, and then calls
+    // it with the arguments supplied.
+    _.delay = function(func, wait) {
+        var args = slice.call(arguments, 2);
+        return setTimeout(function(){
+            return func.apply(null, args);
+        }, wait);
+    };
+
+    // Defers a function, scheduling it to run after the current call stack has
+    // cleared.
+    _.defer = _.partial(_.delay, _, 1);
+
+    // Returns a function, that, when invoked, will only be triggered at most once
+    // during a given window of time. Normally, the throttled function will run
+    // as much as it can, without ever going more than once per `wait` duration;
+    // but if you'd like to disable the execution on the leading edge, pass
+    // `{leading: false}`. To disable execution on the trailing edge, ditto.
+    _.throttle = function(func, wait, options) {
+        var context, args, result;
+        var timeout = null;
+        var previous = 0;
+        if (!options) options = {};
+        var later = function() {
+            previous = options.leading === false ? 0 : _.now();
+            timeout = null;
+            result = func.apply(context, args);
+            if (!timeout) context = args = null;
+        };
+        return function() {
+            var now = _.now();
+            if (!previous && options.leading === false) previous = now;
+            var remaining = wait - (now - previous);
+            context = this;
+            args = arguments;
+            if (remaining <= 0 || remaining > wait) {
+                if (timeout) {
+                    clearTimeout(timeout);
+                    timeout = null;
+                }
+                previous = now;
+                result = func.apply(context, args);
+                if (!timeout) context = args = null;
+            } else if (!timeout && options.trailing !== false) {
+                timeout = setTimeout(later, remaining);
+            }
+            return result;
+        };
+    };
+
+    // Returns a function, that, as long as it continues to be invoked, will not
+    // be triggered. The function will be called after it stops being called for
+    // N milliseconds. If `immediate` is passed, trigger the function on the
+    // leading edge, instead of the trailing.
+    _.debounce = function(func, wait, immediate) {
+        var timeout, args, context, timestamp, result;
+
+        var later = function() {
+            var last = _.now() - timestamp;
+
+            if (last < wait && last >= 0) {
+                timeout = setTimeout(later, wait - last);
+            } else {
+                timeout = null;
+                if (!immediate) {
+                    result = func.apply(context, args);
+                    if (!timeout) context = args = null;
+                }
+            }
+        };
+
+        return function() {
+            context = this;
+            args = arguments;
+            timestamp = _.now();
+            var callNow = immediate && !timeout;
+            if (!timeout) timeout = setTimeout(later, wait);
+            if (callNow) {
+                result = func.apply(context, args);
+                context = args = null;
+            }
+
+            return result;
+        };
+    };
+
+    // Returns the first function passed as an argument to the second,
+    // allowing you to adjust arguments, run code before and after, and
+    // conditionally execute the original function.
+    _.wrap = function(func, wrapper) {
+        return _.partial(wrapper, func);
+    };
+
+    // Returns a negated version of the passed-in predicate.
+    _.negate = function(predicate) {
+        return function() {
+            return !predicate.apply(this, arguments);
+        };
+    };
+
+    // Returns a function that is the composition of a list of functions, each
+    // consuming the return value of the function that follows.
+    _.compose = function() {
+        var args = arguments;
+        var start = args.length - 1;
+        return function() {
+            var i = start;
+            var result = args[start].apply(this, arguments);
+            while (i--) result = args[i].call(this, result);
+            return result;
+        };
+    };
+
+    // Returns a function that will only be executed on and after the Nth call.
+    _.after = function(times, func) {
+        return function() {
+            if (--times < 1) {
+                return func.apply(this, arguments);
+            }
+        };
+    };
+
+    // Returns a function that will only be executed up to (but not including) the Nth call.
+    _.before = function(times, func) {
+        var memo;
+        return function() {
+            if (--times > 0) {
+                memo = func.apply(this, arguments);
+            }
+            if (times <= 1) func = null;
+            return memo;
+        };
+    };
+
+    // Returns a function that will be executed at most one time, no matter how
+    // often you call it. Useful for lazy initialization.
+    _.once = _.partial(_.before, 2);
+
+    // Object Functions
+    // ----------------
+
+    // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
+    var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+    var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+        'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+
+    function collectNonEnumProps(obj, keys) {
+        var nonEnumIdx = nonEnumerableProps.length;
+        var constructor = obj.constructor;
+        var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
+
+        // Constructor is a special case.
+        var prop = 'constructor';
+        if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
+
+        while (nonEnumIdx--) {
+            prop = nonEnumerableProps[nonEnumIdx];
+            if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
+                keys.push(prop);
+            }
+        }
+    }
+
+    // Retrieve the names of an object's own properties.
+    // Delegates to **ECMAScript 5**'s native `Object.keys`
+    _.keys = function(obj) {
+        if (!_.isObject(obj)) return [];
+        if (nativeKeys) return nativeKeys(obj);
+        var keys = [];
+        for (var key in obj) if (_.has(obj, key)) keys.push(key);
+        // Ahem, IE < 9.
+        if (hasEnumBug) collectNonEnumProps(obj, keys);
+        return keys;
+    };
+
+    // Retrieve all the property names of an object.
+    _.allKeys = function(obj) {
+        if (!_.isObject(obj)) return [];
+        var keys = [];
+        for (var key in obj) keys.push(key);
+        // Ahem, IE < 9.
+        if (hasEnumBug) collectNonEnumProps(obj, keys);
+        return keys;
+    };
+
+    // Retrieve the values of an object's properties.
+    _.values = function(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;
+    };
+
+    // Returns the results of applying the iteratee to each element of the object
+    // In contrast to _.map it returns an object
+    _.mapObject = function(obj, iteratee, context) {
+        iteratee = cb(iteratee, context);
+        var keys =  _.keys(obj),
+            length = keys.length,
+            results = {},
+            currentKey;
+        for (var index = 0; index < length; index++) {
+            currentKey = keys[index];
+            results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
+        }
+        return results;
+    };
+
+    // Convert an object into a list of `[key, value]` pairs.
+    _.pairs = function(obj) {
+        var keys = _.keys(obj);
+        var length = keys.length;
+        var pairs = Array(length);
+        for (var i = 0; i < length; i++) {
+            pairs[i] = [keys[i], obj[keys[i]]];
+        }
+        return pairs;
+    };
+
+    // Invert the keys and values of an object. The values must be serializable.
+    _.invert = function(obj) {
+        var result = {};
+        var keys = _.keys(obj);
+        for (var i = 0, length = keys.length; i < length; i++) {
+            result[obj[keys[i]]] = keys[i];
+        }
+        return result;
+    };
+
+    // Return a sorted list of the function names available on the object.
+    // Aliased as `methods`
+    _.functions = _.methods = function(obj) {
+        var names = [];
+        for (var key in obj) {
+            if (_.isFunction(obj[key])) names.push(key);
+        }
+        return names.sort();
+    };
+
+    // Extend a given object with all the properties in passed-in object(s).
+    _.extend = createAssigner(_.allKeys);
+
+    // Assigns a given object with all the own properties in the passed-in object(s)
+    // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+    _.extendOwn = _.assign = createAssigner(_.keys);
+
+    // Returns the first key on an object that passes a predicate test
+    _.findKey = function(obj, predicate, context) {
+        predicate = cb(predicate, context);
+        var keys = _.keys(obj), key;
+        for (var i = 0, length = keys.length; i < length; i++) {
+            key = keys[i];
+            if (predicate(obj[key], key, obj)) return key;
+        }
+    };
+
+    // Return a copy of the object only containing the whitelisted properties.
+    _.pick = function(object, oiteratee, context) {
+        var result = {}, obj = object, iteratee, keys;
+        if (obj == null) return result;
+        if (_.isFunction(oiteratee)) {
+            keys = _.allKeys(obj);
+            iteratee = optimizeCb(oiteratee, context);
+        } else {
+            keys = flatten(arguments, false, false, 1);
+            iteratee = function(value, key, obj) { return key in obj; };
+            obj = Object(obj);
+        }
+        for (var i = 0, length = keys.length; i < length; i++) {
+            var key = keys[i];
+            var value = obj[key];
+            if (iteratee(value, key, obj)) result[key] = value;
+        }
+        return result;
+    };
+
+    // Return a copy of the object without the blacklisted properties.
+    _.omit = function(obj, iteratee, context) {
+        if (_.isFunction(iteratee)) {
+            iteratee = _.negate(iteratee);
+        } else {
+            var keys = _.map(flatten(arguments, false, false, 1), String);
+            iteratee = function(value, key) {
+                return !_.contains(keys, key);
+            };
+        }
+        return _.pick(obj, iteratee, context);
+    };
+
+    // Fill in a given object with default properties.
+    _.defaults = createAssigner(_.allKeys, true);
+
+    // Creates an object that inherits from the given prototype object.
+    // If additional properties are provided then they will be added to the
+    // created object.
+    _.create = function(prototype, props) {
+        var result = baseCreate(prototype);
+        if (props) _.extendOwn(result, props);
+        return result;
+    };
+
+    // Create a (shallow-cloned) duplicate of an object.
+    _.clone = function(obj) {
+        if (!_.isObject(obj)) return obj;
+        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+    };
+
+    // Invokes interceptor with the obj, and then returns obj.
+    // The primary purpose of this method is to "tap into" a method chain, in
+    // order to perform operations on intermediate results within the chain.
+    _.tap = function(obj, interceptor) {
+        interceptor(obj);
+        return obj;
+    };
+
+    // Returns whether an object has a given set of `key:value` pairs.
+    _.isMatch = function(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;
+    };
+
+
+    // Internal recursive comparison function for `isEqual`.
+    var 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;
+        // A strict comparison is necessary because `null == undefined`.
+        if (a == null || b == null) return a === b;
+        // 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;
+        }
+
+        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 = _.keys(a), key;
+            length = keys.length;
+            // Ensure that both objects contain the same number of properties before comparing deep equality.
+            if (_.keys(b).length !== length) return false;
+            while (length--) {
+                // Deep compare each member
+                key = keys[length];
+                if (!(_.has(b, key) && 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;
+    };
+
+    // Perform a deep comparison to check if two objects are equal.
+    _.isEqual = function(a, b) {
+        return eq(a, b);
+    };
+
+    // Is a given array, string, or object empty?
+    // An "empty" object has no enumerable own-properties.
+    _.isEmpty = function(obj) {
+        if (obj == null) return true;
+        if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
+        return _.keys(obj).length === 0;
+    };
+
+    // Is a given value a DOM element?
+    _.isElement = function(obj) {
+        return !!(obj && obj.nodeType === 1);
+    };
+
+    // Is a given value an array?
+    // Delegates to ECMA5's native Array.isArray
+    _.isArray = nativeIsArray || function(obj) {
+        return toString.call(obj) === '[object Array]';
+    };
+
+    // Is a given variable an object?
+    _.isObject = function(obj) {
+        var type = typeof obj;
+        return type === 'function' || type === 'object' && !!obj;
+    };
+
+    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
+    _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
+        _['is' + name] = function(obj) {
+            return toString.call(obj) === '[object ' + name + ']';
+        };
+    });
+
+    // Define a fallback version of the method in browsers (ahem, IE < 9), where
+    // there isn't any inspectable "Arguments" type.
+    if (!_.isArguments(arguments)) {
+        _.isArguments = function(obj) {
+            return _.has(obj, 'callee');
+        };
+    }
+
+    // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
+    // IE 11 (#1621), and in Safari 8 (#1929).
+    if (typeof /./ != 'function' && typeof Int8Array != 'object') {
+        _.isFunction = function(obj) {
+            return typeof obj == 'function' || false;
+        };
+    }
+
+    // Is a given object a finite number?
+    _.isFinite = function(obj) {
+        return isFinite(obj) && !isNaN(parseFloat(obj));
+    };
+
+    // Is the given value `NaN`? (NaN is the only number which does not equal itself).
+    _.isNaN = function(obj) {
+        return _.isNumber(obj) && obj !== +obj;
+    };
+
+    // Is a given value a boolean?
+    _.isBoolean = function(obj) {
+        return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
+    };
+
+    // Is a given value equal to null?
+    _.isNull = function(obj) {
+        return obj === null;
+    };
+
+    // Is a given variable undefined?
+    _.isUndefined = function(obj) {
+        return obj === void 0;
+    };
+
+    // Shortcut function for checking if an object has a given property directly
+    // on itself (in other words, not on a prototype).
+    _.has = function(obj, key) {
+        return obj != null && hasOwnProperty.call(obj, key);
+    };
+
+    // Utility Functions
+    // -----------------
+
+    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+    // previous owner. Returns a reference to the Underscore object.
+    _.noConflict = function() {
+        root._ = previousUnderscore;
+        return this;
+    };
+
+    // Keep the identity function around for default iteratees.
+    _.identity = function(value) {
+        return value;
+    };
+
+    // Predicate-generating functions. Often useful outside of Underscore.
+    _.constant = function(value) {
+        return function() {
+            return value;
+        };
+    };
+
+    _.noop = function(){};
+
+    _.property = function(key) {
+        return function(obj) {
+            return obj == null ? void 0 : obj[key];
+        };
+    };
+
+    // Generates a function for a given object that returns a given property.
+    _.propertyOf = function(obj) {
+        return obj == null ? function(){} : function(key) {
+            return obj[key];
+        };
+    };
+
+    // Returns a predicate for checking whether an object has a given set of
+    // `key:value` pairs.
+    _.matcher = _.matches = function(attrs) {
+        attrs = _.extendOwn({}, attrs);
+        return function(obj) {
+            return _.isMatch(obj, attrs);
+        };
+    };
+
+    // Run a function **n** times.
+    _.times = function(n, iteratee, context) {
+        var accum = Array(Math.max(0, n));
+        iteratee = optimizeCb(iteratee, context, 1);
+        for (var i = 0; i < n; i++) accum[i] = iteratee(i);
+        return accum;
+    };
+
+    // Return a random integer between min and max (inclusive).
+    _.random = function(min, max) {
+        if (max == null) {
+            max = min;
+            min = 0;
+        }
+        return min + Math.floor(Math.random() * (max - min + 1));
+    };
+
+    // A (possibly faster) way to get the current timestamp as an integer.
+    _.now = Date.now || function() {
+        return new Date().getTime();
+    };
+
+    // List of HTML entities for escaping.
+    var escapeMap = {
+        '&': '&amp;',
+        '<': '&lt;',
+        '>': '&gt;',
+        '"': '&quot;',
+        "'": '&#x27;',
+        '`': '&#x60;'
+    };
+    var unescapeMap = _.invert(escapeMap);
+
+    // Functions for escaping and unescaping strings to/from HTML interpolation.
+    var createEscaper = function(map) {
+        var escaper = function(match) {
+            return map[match];
+        };
+        // Regexes for identifying a key that needs to be escaped
+        var source = '(?:' + _.keys(map).join('|') + ')';
+        var testRegexp = RegExp(source);
+        var replaceRegexp = RegExp(source, 'g');
+        return function(string) {
+            string = string == null ? '' : '' + string;
+            return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+        };
+    };
+    _.escape = createEscaper(escapeMap);
+    _.unescape = createEscaper(unescapeMap);
+
+    // If the value of the named `property` is a function then invoke it with the
+    // `object` as context; otherwise, return it.
+    _.result = function(object, property, fallback) {
+        var value = object == null ? void 0 : object[property];
+        if (value === void 0) {
+            value = fallback;
+        }
+        return _.isFunction(value) ? value.call(object) : value;
+    };
+
+    // Generate a unique integer id (unique within the entire client session).
+    // Useful for temporary DOM ids.
+    var idCounter = 0;
+    _.uniqueId = function(prefix) {
+        var id = ++idCounter + '';
+        return prefix ? prefix + id : id;
+    };
+
+    // By default, Underscore uses ERB-style template delimiters, change the
+    // following template settings to use alternative delimiters.
+    _.templateSettings = {
+        evaluate    : /<%([\s\S]+?)%>/g,
+        interpolate : /<%=([\s\S]+?)%>/g,
+        escape      : /<%-([\s\S]+?)%>/g
+    };
+
+    // When customizing `templateSettings`, if you don't want to define an
+    // interpolation, evaluation or escaping regex, we need one that is
+    // guaranteed not to match.
+    var noMatch = /(.)^/;
+
+    // Certain characters need to be escaped so that they can be put into a
+    // string literal.
+    var escapes = {
+        "'":      "'",
+        '\\':     '\\',
+        '\r':     'r',
+        '\n':     'n',
+        '\u2028': 'u2028',
+        '\u2029': 'u2029'
+    };
+
+    var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
+
+    var escapeChar = function(match) {
+        return '\\' + escapes[match];
+    };
+
+    // JavaScript micro-templating, similar to John Resig's implementation.
+    // Underscore templating handles arbitrary delimiters, preserves whitespace,
+    // and correctly escapes quotes within interpolated code.
+    // NB: `oldSettings` only exists for backwards compatibility.
+    _.template = function(text, settings, oldSettings) {
+        if (!settings && oldSettings) settings = oldSettings;
+        settings = _.defaults({}, settings, _.templateSettings);
+
+        // Combine delimiters into one regular expression via alternation.
+        var matcher = RegExp([
+            (settings.escape || noMatch).source,
+            (settings.interpolate || noMatch).source,
+            (settings.evaluate || noMatch).source
+        ].join('|') + '|$', 'g');
+
+        // Compile the template source, escaping string literals appropriately.
+        var index = 0;
+        var source = "__p+='";
+        text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+            source += text.slice(index, offset).replace(escaper, escapeChar);
+            index = offset + match.length;
+
+            if (escape) {
+                source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+            } else if (interpolate) {
+                source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+            } else if (evaluate) {
+                source += "';\n" + evaluate + "\n__p+='";
+            }
+
+            // Adobe VMs need the match returned to produce the correct offest.
+            return match;
+        });
+        source += "';\n";
+
+        // If a variable is not specified, place data values in local scope.
+        if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+        source = "var __t,__p='',__j=Array.prototype.join," +
+            "print=function(){__p+=__j.call(arguments,'');};\n" +
+            source + 'return __p;\n';
+
+        try {
+            var render = new Function(settings.variable || 'obj', '_', source);
+        } catch (e) {
+            e.source = source;
+            throw e;
+        }
+
+        var template = function(data) {
+            return render.call(this, data, _);
+        };
+
+        // Provide the compiled source as a convenience for precompilation.
+        var argument = settings.variable || 'obj';
+        template.source = 'function(' + argument + '){\n' + source + '}';
+
+        return template;
+    };
+
+    // Add a "chain" function. Start chaining a wrapped Underscore object.
+    _.chain = function(obj) {
+        var instance = _(obj);
+        instance._chain = true;
+        return instance;
+    };
+
+    // OOP
+    // ---------------
+    // If Underscore is called as a function, it returns a wrapped object that
+    // can be used OO-style. This wrapper holds altered versions of all the
+    // underscore functions. Wrapped objects may be chained.
+
+    // Helper function to continue chaining intermediate results.
+    var result = function(instance, obj) {
+        return instance._chain ? _(obj).chain() : obj;
+    };
+
+    // Add your own custom functions to the Underscore object.
+    _.mixin = function(obj) {
+        _.each(_.functions(obj), function(name) {
+            var func = _[name] = obj[name];
+            _.prototype[name] = function() {
+                var args = [this._wrapped];
+                push.apply(args, arguments);
+                return result(this, func.apply(_, args));
+            };
+        });
+    };
+
+    // Add all of the Underscore functions to the wrapper object.
+    _.mixin(_);
+
+    // Add all mutator Array functions to the wrapper.
+    _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+        var method = ArrayProto[name];
+        _.prototype[name] = function() {
+            var obj = this._wrapped;
+            method.apply(obj, arguments);
+            if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+            return result(this, obj);
+        };
+    });
+
+    // Add all accessor Array functions to the wrapper.
+    _.each(['concat', 'join', 'slice'], function(name) {
+        var method = ArrayProto[name];
+        _.prototype[name] = function() {
+            return result(this, method.apply(this._wrapped, arguments));
+        };
+    });
+
+    // Extracts the result from a wrapped and chained object.
+    _.prototype.value = function() {
+        return this._wrapped;
+    };
+
+    // Provide unwrapping proxy for some methods used in engine operations
+    // such as arithmetic and JSON stringification.
+    _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
+
+    _.prototype.toString = function() {
+        return '' + this._wrapped;
+    };
+
+    // AMD registration happens at the end for compatibility with AMD loaders
+    // that may not enforce next-turn semantics on modules. Even though general
+    // practice for AMD registration is to be anonymous, underscore registers
+    // as a named module because, like jQuery, it is a base library that is
+    // popular enough to be bundled in a third party lib, but not be part of
+    // an AMD load request. Those cases could generate an error when an
+    // anonymous define() is called outside of a loader request.
+    if (typeof define === 'function' && define.amd) {
+        define('underscore', [], function() {
+            return _;
+        });
+    }
+}.call(this));/**
+ * Created by richie on 15/7/8.
+ */
+/**
+ * 初始化BI对象
+ */
+if (window.BI == null) {
+    window.BI = {};
+}/**
+ * MVC工厂
+ * guy
+ * @class BI.Factory
+ */
+BI.Factory = {
+    parsePath: function parsePath (path) {
+        var segments = path.split('.');
+        return function (obj) {
+            for (var i = 0; i < segments.length; i++) {
+                if (!obj) {
+                    return;
+                }
+                obj = obj[segments[i]];
+            }
+            return obj;
+        }
+    },
+    createView : function(url, viewFunc, mData, vData, context){
+        var modelFunc = viewFunc.replace(/View/, "Model");
+        modelFunc = this.parsePath(modelFunc)(window);
+        if(!_.isFunction(modelFunc)){
+            modelFunc = BI.Model;
+        }
+//        try {
+            var model = new (modelFunc)(_.extend({}, mData, {
+                    parent: context && context.model,
+                    rootURL: url
+            }), {silent: true});
+//        } catch (e) {
+//
+//        }
+//        try {
+        var view = new (eval(viewFunc))(_.extend({}, vData, {
+            model: model,
+            parent: context,
+            rootURL: url
+        }));
+//        } catch (e) {
+//
+//        }
+        return view;
+    }
+};(function(root, factory) {
+        root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$));
+}(this, function(root, BI, _, $) {
+
+    var previousBI = root.BI;
+
+    // Create local references to array methods we'll want to use later.
+    var array = [];
+    var slice = array.slice;
+
+    // Current version of the library. Keep in sync with `package.json`.
+    BI.VERSION = '1.0.0';
+
+    // For BI's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
+    // the `$` variable.
+    BI.$ = $;
+
+    // Runs BI.js in *noConflict* mode, returning the `BI` variable
+    // to its previous owner. Returns a reference to this BI object.
+    BI.noConflict = function() {
+        root.BI = previousBI;
+        return this;
+    };
+
+    // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
+    // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
+    // set a `X-Http-Method-Override` header.
+    BI.emulateHTTP = true;
+
+    // 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`.
+    BI.emulateJSON = true;
+
+    // BI.Events
+    // ---------------
+
+    // A module that can be mixed in to *any object* in order to provide it with
+    // custom events. You may bind with `on` or remove with `off` callback
+    // functions to an event; `trigger`-ing an event fires all callbacks in
+    // succession.
+    //
+    //     var object = {};
+    //     _.extend(object, BI.Events);
+    //     object.on('expand', function(){ alert('expanded'); });
+    //     object.trigger('expand');
+    //
+    var Events = BI.Events = {
+
+        // Bind an event to a `callback` function. Passing `"all"` will bind
+        // the callback to all events fired.
+        on: function(name, callback, context) {
+            if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
+            this._events || (this._events = {});
+            var events = this._events[name] || (this._events[name] = []);
+            events.push({callback: callback, context: context, ctx: context || this});
+            return this;
+        },
+
+        // Bind an event to only be triggered a single time. After the first time
+        // the callback is invoked, it will be removed.
+        once: function(name, callback, context) {
+            if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
+            var self = this;
+            var once = _.once(function() {
+                self.off(name, once);
+                callback.apply(this, arguments);
+            });
+            once._callback = callback;
+            return this.on(name, once, context);
+        },
+
+        // Remove one or many callbacks. If `context` is null, removes all
+        // callbacks with that function. If `callback` is null, removes all
+        // callbacks for the event. If `name` is null, removes all bound
+        // callbacks for all events.
+        off: function(name, callback, context) {
+            if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
+
+            // Remove all callbacks for all events.
+            if (!name && !callback && !context) {
+                this._events = void 0;
+                return this;
+            }
+
+            var names = name ? [name] : _.keys(this._events);
+            for (var i = 0, length = names.length; i < length; i++) {
+                name = names[i];
+
+                // Bail out if there are no events stored.
+                var events = this._events[name];
+                if (!events) continue;
+
+                // Remove all callbacks for this event.
+                if (!callback && !context) {
+                    delete this._events[name];
+                    continue;
+                }
+
+                // Find any remaining events.
+                var remaining = [];
+                for (var j = 0, k = events.length; j < k; j++) {
+                    var event = events[j];
+                    if (
+                        callback && callback !== event.callback &&
+                        callback !== event.callback._callback ||
+                        context && context !== event.context
+                        ) {
+                        remaining.push(event);
+                    }
+                }
+
+                // Replace events if there are any remaining.  Otherwise, clean up.
+                if (remaining.length) {
+                    this._events[name] = remaining;
+                } else {
+                    delete this._events[name];
+                }
+            }
+
+            return this;
+        },
+
+        // Trigger one or many events, firing all bound callbacks. Callbacks are
+        // passed the same arguments as `trigger` is, apart from the event name
+        // (unless you're listening on `"all"`, which will cause your callback to
+        // receive the true name of the event as the first argument).
+        trigger: function(name) {
+            if (!this._events) return this;
+            var args = slice.call(arguments, 1);
+            if (!eventsApi(this, 'trigger', name, args)) return this;
+            var events = this._events[name];
+            var allEvents = this._events.all;
+            if (events) triggerEvents(events, args);
+            if (allEvents) triggerEvents(allEvents, arguments);
+            return this;
+        },
+
+        // Inversion-of-control versions of `on` and `once`. Tell *this* object to
+        // listen to an event in another object ... keeping track of what it's
+        // listening to.
+        listenTo: function(obj, name, callback) {
+            var listeningTo = this._listeningTo || (this._listeningTo = {});
+            var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
+            listeningTo[id] = obj;
+            if (!callback && typeof name === 'object') callback = this;
+            obj.on(name, callback, this);
+            return this;
+        },
+
+        listenToOnce: function(obj, name, callback) {
+            if (typeof name === 'object') {
+                for (var event in name) this.listenToOnce(obj, event, name[event]);
+                return this;
+            }
+            if (eventSplitter.test(name)) {
+                var names = name.split(eventSplitter);
+                for (var i = 0, length = names.length; i < length; i++) {
+                    this.listenToOnce(obj, names[i], callback);
+                }
+                return this;
+            }
+            if (!callback) return this;
+            var once = _.once(function() {
+                this.stopListening(obj, name, once);
+                callback.apply(this, arguments);
+            });
+            once._callback = callback;
+            return this.listenTo(obj, name, once);
+        },
+
+        // Tell this object to stop listening to either specific events ... or
+        // to every object it's currently listening to.
+        stopListening: function(obj, name, callback) {
+            var listeningTo = this._listeningTo;
+            if (!listeningTo) return this;
+            var remove = !name && !callback;
+            if (!callback && typeof name === 'object') callback = this;
+            if (obj) (listeningTo = {})[obj._listenId] = obj;
+            for (var id in listeningTo) {
+                obj = listeningTo[id];
+                obj.off(name, callback, this);
+                if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
+            }
+            return this;
+        }
+
+    };
+
+    // Regular expression used to split event strings.
+    var eventSplitter = /\s+/;
+
+    // Implement fancy features of the Events API such as multiple event
+    // names `"change blur"` and jQuery-style event maps `{change: action}`
+    // in terms of the existing API.
+    var eventsApi = function(obj, action, name, rest) {
+        if (!name) return true;
+
+        // Handle event maps.
+        if (typeof name === 'object') {
+            for (var key in name) {
+                obj[action].apply(obj, [key, name[key]].concat(rest));
+            }
+            return false;
+        }
+
+        // Handle space separated event names.
+        if (eventSplitter.test(name)) {
+            var names = name.split(eventSplitter);
+            for (var i = 0, length = names.length; i < length; i++) {
+                obj[action].apply(obj, [names[i]].concat(rest));
+            }
+            return false;
+        }
+
+        return true;
+    };
+
+    // A difficult-to-believe, but optimized internal dispatch function for
+    // triggering events. Tries to keep the usual cases speedy (most internal
+    // BI events have 3 arguments).
+    var triggerEvents = function(events, args) {
+        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
+        switch (args.length) {
+            case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
+            case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
+            case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
+            case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
+            default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
+        }
+    };
+
+    // Aliases for backwards compatibility.
+    Events.bind   = Events.on;
+    Events.unbind = Events.off;
+
+    // Allow the `BI` object to serve as a global event bus, for folks who
+    // want global "pubsub" in a convenient place.
+    _.extend(BI, Events);
+
+    // BI.M
+    // --------------
+
+    // BI **Models** are the basic data object in the framework --
+    // frequently representing a row in a table in a database on your server.
+    // A discrete chunk of data and a bunch of useful, related methods for
+    // performing computations and transformations on that data.
+
+    // Create a new model with the specified attributes. A client id (`cid`)
+    // is automatically generated and assigned for you.
+    var M = BI.M = function(attributes, options) {
+        var attrs = attributes || {};
+        options = options || {};
+        this.cid = _.uniqueId('c');
+        this.attributes = {};
+        if (options.collection) this.collection = options.collection;
+        if (options.parse) attrs = this.parse(attrs, options) || {};
+        this.options = attrs = _.defaults({}, attrs, _.result(this, '_defaultConfig'));
+        _.extend(this, _.pick(this.options, modelOptions));
+        this.set(attrs, options);
+        this.changed = {};
+        this._init.apply(this, arguments);
+    };
+
+    var modelOptions = ['rootURL', 'parent', 'data', 'id'];
+
+    // Attach all inheritable methods to the M prototype.
+    _.extend(M.prototype, Events, {
+
+        // 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',
+
+        _defaultConfig: function(){return {}},
+        // _init is an empty function by default. Override it with your own
+        // initialization logic.
+        _init: function(){},
+
+        // Return a copy of the model's `attributes` object.
+        toJSON: function(options) {
+            return _.clone(this.attributes);
+        },
+
+        // Proxy `BI.sync` by default -- but override this if you need
+        // custom syncing semantics for *this* particular model.
+        sync: function() {
+            return BI.sync.apply(this, arguments);
+        },
+
+        // Get the value of an attribute.
+        get: function(attr) {
+            return this.attributes[attr];
+        },
+
+        // Get the HTML-escaped value of an attribute.
+        escape: function(attr) {
+            return _.escape(this.get(attr));
+        },
+
+        // Returns `true` if the attribute contains a value that is not null
+        // or undefined.
+        has: function(attr) {
+            return _.has(this.attributes, attr);
+        },
+
+        // Special-cased proxy to underscore's `_.matches` method.
+        matches: function(attrs) {
+            var keys = _.keys(attrs), length = keys.length;
+            var obj = Object(this.attributes);
+            for (var i = 0; i < length; i++) {
+                var key = keys[i];
+                if (!_.isEqual(attrs[key], obj[key]) || !(key in obj)) return false;
+            }
+            return true;
+        },
+
+        // 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) {
+            var attr, attrs, unset, changes, silent, changing, changed, prev, current;
+            if (key == null) return this;
+
+            // Handle both `"key", value` and `{key: value}` -style arguments.
+            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.
+            unset           = options.unset;
+            silent          = options.silent;
+            changes         = [];
+            changing        = this._changing;
+            this._changing  = true;
+
+            if (!changing) {
+                this._previousAttributes = _.clone(this.attributes);
+                this.changed = {};
+            }
+            current = this.attributes, prev = this._previousAttributes;
+
+            // Check for changes of `id`.
+            if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
+
+            // For each `set` attribute, update or delete the current value.
+            for (attr in attrs) {
+                val = attrs[attr];
+                if (!_.isEqual(current[attr], val)) changes.push(attr);
+                if (!_.isEqual(prev[attr], val)) {
+                    this.changed[attr] = val;
+                } else {
+                    delete this.changed[attr];
+                }
+                unset ? delete current[attr] : current[attr] = val;
+            }
+
+            // Trigger all relevant attribute changes.
+            if (!silent) {
+                if (changes.length) this._pending = options;
+                for (var i = 0, length = changes.length; i < 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;
+            changed = BI.clone(this.changed);
+            if (!silent) {
+                while (this._pending) {
+                    options = this._pending;
+                    this._pending = false;
+                    this.trigger('change', changed, prev, this, options);
+                }
+            }
+            this._pending = false;
+            this._changing = false;
+            if (!silent && changes.length) this.trigger("changed", changed, prev, this, options);
+            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, _.extend({}, 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, _.extend({}, 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 !_.isEmpty(this.changed);
+            return _.has(this.changed, attr);
+        },
+
+        // 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 val, changed = false;
+            var old = this._changing ? this._previousAttributes : this.attributes;
+            for (var attr in diff) {
+                if (_.isEqual(old[attr], (val = diff[attr]))) continue;
+                (changed || (changed = {}))[attr] = val;
+            }
+            return changed;
+        },
+
+        // 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);
+        },
+
+        // Fetch the model from the server. If the server's representation of the
+        // model differs from its current attributes, they will be overridden,
+        // triggering a `"change"` event.
+        fetch: function(options) {
+            options = options ? _.clone(options) : {};
+            if (options.parse === void 0) options.parse = true;
+            var model = this;
+            var success = options.success;
+            options.success = function(resp) {
+                if(!options.noset) {
+                    if (!model.set(model.parse(resp, options), options)) return false;
+                }
+                if (success) success(resp, model, options);
+                model.trigger('sync', resp, model, options).trigger('read', resp, model, options);
+            };
+            wrapError(this, options);
+            return this.sync('read', this, options);
+        },
+
+        // Set a hash of model attributes, and sync the model to the server.
+        // If the server returns an attributes hash that differs, the model's
+        // state will be `set` again.
+        save: function(key, val, options) {
+            var attrs, method, xhr, attributes = this.attributes;
+
+            // Handle both `"key", value` and `{key: value}` -style arguments.
+            if (key == null || typeof key === 'object') {
+                attrs = key;
+                options = val;
+            } else {
+                (attrs = {})[key] = val;
+            }
+
+            options = _.extend({validate: true}, options);
+
+            // If we're not waiting and attributes exist, save acts as
+            // `set(attr).save(null, opts)` with validation. Otherwise, check if
+            // the model will be valid when the attributes, if any, are set.
+            if (attrs && !options.wait) {
+                if (!this.set(attrs, options)) return false;
+            } else {
+                if (!this._validate(attrs, options)) return false;
+            }
+
+            // Set temporary attributes if `{wait: true}`.
+            if (attrs && options.wait) {
+                this.attributes = _.extend({}, attributes, attrs);
+            }
+
+            // After a successful server-side save, the client is (optionally)
+            // updated with the server-side state.
+            if (options.parse === void 0) options.parse = true;
+            var model = this;
+            var success = options.success;
+            options.success = function(resp) {
+                // Ensure attributes are restored during synchronous saves.
+                model.attributes = attributes;
+                var serverAttrs = model.parse(resp, options);
+                if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
+                if (_.isObject(serverAttrs) && !options.noset && !model.set(serverAttrs, options)) {
+                    return false;
+                }
+                if (success) success(resp, model, options);
+                model.trigger('sync', resp, model, options)
+                    .trigger((options.patch ? 'patch' : 'update'), resp, model, options);
+            };
+            wrapError(this, options);
+
+            method = /**this.isNew() ? 'create' :**/ (options.patch ? 'patch' : 'update');
+            if (method === 'patch' && !options.attrs) options.attrs = attrs;
+            xhr = this.sync(method, this, options);
+
+            // Restore attributes.
+            if (attrs && options.wait) this.attributes = attributes;
+
+            return xhr;
+        },
+
+        // Destroy this model on the server if it was already persisted.
+        // Optimistically removes the model 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 ? _.clone(options) : {};
+            var model = this;
+            var success = options.success;
+
+            var destroy = function() {
+                model.stopListening();
+                model.trigger('destroy', model.collection, model, options);
+            };
+
+            options.success = function(resp) {
+                if (options.wait || model.isNew()) destroy();
+                if (success) success(resp, model, options);
+                if (!model.isNew()) model.trigger('sync', resp, model, options).trigger('delete', resp, model, options);
+            };
+
+            if (this.isNew()) {
+                options.success();
+                return false;
+            }
+            wrapError(this, options);
+
+            var xhr = this.sync('delete', this, options);
+            if (!options.wait) destroy();
+            return xhr;
+        },
+
+        // Default URL for the model's representation on the server -- if you're
+        // using BI's restful methods, override this to change the endpoint
+        // that will be called.
+        url: function() {
+            var base =
+                _.result(this.collection, 'url');
+            if (this.isNew()) return base;
+            return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
+        },
+
+        // **parse** converts a response into the hash of attributes to be `set` on
+        // the model. The default implementation is just to pass the response along.
+        parse: function(resp, options) {
+            return resp;
+        },
+
+        // 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({}, _.extend(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 = _.extend({}, this.attributes, attrs);
+            var error = this.validationError = this.validate(attrs, options) || null;
+            if (!error) return true;
+            this.trigger('invalid', error, this, _.extend(options, {validationError: error}));
+            return false;
+        }
+
+    });
+
+    // Underscore methods that we want to implement on the M.
+    var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit', 'chain', 'isEmpty'];
+
+    // Mix in each Underscore method as a proxy to `M#attributes`.
+    _.each(modelMethods, function(method) {
+        if (!_[method]) return;
+        M.prototype[method] = function() {
+            var args = slice.call(arguments);
+            args.unshift(this.attributes);
+            return _[method].apply(_, args);
+        };
+    });
+
+    // BI.Collection
+    // -------------------
+
+    // If models tend to represent a single row of data, a BI Collection is
+    // more analogous to a table full of data ... or a small slice or page of that
+    // table, or a collection of rows that belong together for a particular reason
+    // -- all of the messages in this particular folder, all of the documents
+    // belonging to this particular author, and so on. Collections maintain
+    // indexes of their models, both in order, and for lookup by `id`.
+
+    // Create a new **Collection**, perhaps to contain a specific type of `model`.
+    // If a `comparator` is specified, the Collection will maintain
+    // its models in sort order, as they're added and removed.
+    var Collection = BI.Collection = function(models, options) {
+        this.options = options = options || {};
+        if (options.model) this.model = options.model;
+        if (options.comparator !== void 0) this.comparator = options.comparator;
+        this._reset();
+        this._init.apply(this, arguments);
+        if (models) this.reset(models, _.extend({silent: true}, options));
+    };
+
+    // Default options for `Collection#set`.
+    var setOptions = {add: true, remove: true, merge: true};
+    var addOptions = {add: true, remove: false};
+
+    // Define the Collection's inheritable methods.
+    _.extend(Collection.prototype, Events, {
+
+        // The default model for a collection is just a **BI.M**.
+        // This should be overridden in most cases.
+        model: M,
+
+        // _init is an empty function by default. Override it with your own
+        // initialization logic.
+        _init: function(){},
+
+        // The JSON representation of a Collection is an array of the
+        // models' attributes.
+        toJSON: function(options) {
+            return this.map(function(model){ return model.toJSON(options); });
+        },
+
+        // Proxy `BI.sync` by default.
+        sync: function() {
+            return BI.sync.apply(this, arguments);
+        },
+
+        // Add a model, or list of models to the set.
+        add: function(models, options) {
+            return this.set(models, _.extend({merge: false}, options, addOptions));
+        },
+
+        // Remove a model, or a list of models from the set.
+        remove: function(models, options) {
+            var singular = !_.isArray(models);
+            models = singular ? [models] : _.clone(models);
+            options || (options = {});
+            for (var i = 0, length = models.length; i < length; i++) {
+                var model = models[i] = this.get(models[i]);
+                if (!model) continue;
+                var id = this.modelId(model.attributes);
+                if (id != null) delete this._byId[id];
+                delete this._byId[model.cid];
+                var index = this.indexOf(model);
+                this.models.splice(index, 1);
+                this.length--;
+                if (!options.silent) {
+                    options.index = index;
+                    model.trigger('remove', model, this, options);
+                }
+                this._removeReference(model, options);
+            }
+            return singular ? models[0] : models;
+        },
+
+        // Update a collection by `set`-ing a new list of models, adding new ones,
+        // removing models that are no longer present, and merging models that
+        // already exist in the collection, as necessary. Similar to **M#set**,
+        // the core operation for updating the data contained by the collection.
+        set: function(models, options) {
+            options = _.defaults({}, options, setOptions);
+            if (options.parse) models = this.parse(models, options);
+            var singular = !_.isArray(models);
+            models = singular ? (models ? [models] : []) : models.slice();
+            var id, model, attrs, existing, sort;
+            var at = options.at;
+            if (at != null) at = +at;
+            if (at < 0) at += this.length + 1;
+            var sortable = this.comparator && (at == null) && options.sort !== false;
+            var sortAttr = _.isString(this.comparator) ? this.comparator : null;
+            var toAdd = [], toRemove = [], modelMap = {};
+            var add = options.add, merge = options.merge, remove = options.remove;
+            var order = !sortable && add && remove ? [] : false;
+            var orderChanged = false;
+
+            // Turn bare objects into model references, and prevent invalid models
+            // from being added.
+            for (var i = 0, length = models.length; i < length; i++) {
+                attrs = models[i];
+
+                // If a duplicate is found, prevent it from being added and
+                // optionally merge it into the existing model.
+                if (existing = this.get(attrs)) {
+                    if (remove) modelMap[existing.cid] = true;
+                    if (merge && attrs !== existing) {
+                        attrs = this._isModel(attrs) ? attrs.attributes : attrs;
+                        if (options.parse) attrs = existing.parse(attrs, options);
+                        existing.set(attrs, options);
+                        if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
+                    }
+                    models[i] = existing;
+
+                    // If this is a new, valid model, push it to the `toAdd` list.
+                } else if (add) {
+                    model = models[i] = this._prepareModel(attrs, options);
+                    if (!model) continue;
+                    toAdd.push(model);
+                    this._addReference(model, options);
+                }
+
+                // Do not add multiple models with the same `id`.
+                model = existing || model;
+                if (!model) continue;
+                id = this.modelId(model.attributes);
+                if (order && (model.isNew() || !modelMap[id])) {
+                    order.push(model);
+
+                    // Check to see if this is actually a new model at this index.
+                    orderChanged = orderChanged || !this.models[i] || model.cid !== this.models[i].cid;
+                }
+
+                modelMap[id] = true;
+            }
+
+            // Remove nonexistent models if appropriate.
+            if (remove) {
+                for (var i = 0, length = this.length; i < length; i++) {
+                    if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
+                }
+                if (toRemove.length) this.remove(toRemove, options);
+            }
+
+            // See if sorting is needed, update `length` and splice in new models.
+            if (toAdd.length || orderChanged) {
+                if (sortable) sort = true;
+                this.length += toAdd.length;
+                if (at != null) {
+                    for (var i = 0, length = toAdd.length; i < length; i++) {
+                        this.models.splice(at + i, 0, toAdd[i]);
+                    }
+                } else {
+                    if (order) this.models.length = 0;
+                    var orderedModels = order || toAdd;
+                    for (var i = 0, length = orderedModels.length; i < length; i++) {
+                        this.models.push(orderedModels[i]);
+                    }
+                }
+            }
+
+            // Silently sort the collection if appropriate.
+            if (sort) this.sort({silent: true});
+
+            // Unless silenced, it's time to fire all appropriate add/sort events.
+            if (!options.silent) {
+                var addOpts = at != null ? _.clone(options) : options;
+                for (var i = 0, length = toAdd.length; i < length; i++) {
+                    if (at != null) addOpts.index = at + i;
+                    (model = toAdd[i]).trigger('add', model, this, addOpts);
+                }
+                if (sort || orderChanged) this.trigger('sort', this, options);
+            }
+
+            // Return the added (or merged) model (or models).
+            return singular ? models[0] : models;
+        },
+
+        // When you have more items than you want to add or remove individually,
+        // you can reset the entire set with a new list of models, without firing
+        // any granular `add` or `remove` events. Fires `reset` when finished.
+        // Useful for bulk operations and optimizations.
+        reset: function(models, options) {
+            options = options ? _.clone(options) : {};
+            for (var i = 0, length = this.models.length; i < length; i++) {
+                this._removeReference(this.models[i], options);
+            }
+            options.previousModels = this.models;
+            this._reset();
+            models = this.add(models, _.extend({silent: true}, options));
+            if (!options.silent) this.trigger('reset', this, options);
+            return models;
+        },
+
+        // Add a model to the end of the collection.
+        push: function(model, options) {
+            return this.add(model, _.extend({at: this.length}, options));
+        },
+
+        // Remove a model from the end of the collection.
+        pop: function(options) {
+            var model = this.at(this.length - 1);
+            this.remove(model, options);
+            return model;
+        },
+
+        // Add a model to the beginning of the collection.
+        unshift: function(model, options) {
+            return this.add(model, _.extend({at: 0}, options));
+        },
+
+        // Remove a model from the beginning of the collection.
+        shift: function(options) {
+            var model = this.at(0);
+            this.remove(model, options);
+            return model;
+        },
+
+        // Slice out a sub-array of models from the collection.
+        slice: function() {
+            return slice.apply(this.models, arguments);
+        },
+
+        // Get a model from the set by id.
+        get: function(obj) {
+            if (obj == null) return void 0;
+            var id = this.modelId(this._isModel(obj) ? obj.attributes : obj);
+            return this._byId[obj] || this._byId[id] || this._byId[obj.cid];
+        },
+
+        // Get the model at the given index.
+        at: function(index) {
+            if (index < 0) index += this.length;
+            return this.models[index];
+        },
+
+        // Return models with matching attributes. Useful for simple cases of
+        // `filter`.
+        where: function(attrs, first) {
+            var matches = _.matches(attrs);
+            return this[first ? 'find' : 'filter'](function(model) {
+                return matches(model.attributes);
+            });
+        },
+
+        // Return the first model 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) {
+            if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
+            options || (options = {});
+
+            // Run sort based on type of `comparator`.
+            if (_.isString(this.comparator) || this.comparator.length === 1) {
+                this.models = this.sortBy(this.comparator, this);
+            } else {
+                this.models.sort(_.bind(this.comparator, this));
+            }
+
+            if (!options.silent) this.trigger('sort', this, options);
+            return this;
+        },
+
+        // Pluck an attribute from each model in the collection.
+        pluck: function(attr) {
+            return _.invoke(this.models, 'get', attr);
+        },
+
+        // Fetch the default set of models 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 = options ? _.clone(options) : {};
+            if (options.parse === void 0) options.parse = true;
+            var success = options.success;
+            var collection = this;
+            options.success = function(resp) {
+                var method = options.reset ? 'reset' : 'set';
+                collection[method](resp, options);
+                if (success) success(collection, resp, options);
+                collection.trigger('sync', collection, resp, options);
+            };
+            wrapError(this, options);
+            return this.sync('read', this, options);
+        },
+
+        // Create a new instance of a model in this collection. Add the model to the
+        // collection immediately, unless `wait: true` is passed, in which case we
+        // wait for the server to agree.
+        create: function(model, options) {
+            options = options ? _.clone(options) : {};
+            if (!(model = this._prepareModel(model, options))) return false;
+            if (!options.wait) this.add(model, options);
+            var collection = this;
+            var success = options.success;
+            options.success = function(model, resp) {
+                if (options.wait) collection.add(model, options);
+                if (success) success(model, resp, options);
+            };
+            model.save(null, options);
+            return model;
+        },
+
+        // **parse** converts a response into a list of models 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 models as this one.
+        clone: function() {
+            return new this.constructor(this.models, {
+                model: this.model,
+                comparator: this.comparator
+            });
+        },
+
+        // Define how to uniquely identify models in the collection.
+        modelId: function (attrs) {
+            return attrs[this.model.prototype.idAttribute || 'id'];
+        },
+
+        // Private method to reset all internal state. Called when the collection
+        // is first _initd or reset.
+        _reset: function() {
+            this.length = 0;
+            this.models = [];
+            this._byId  = {};
+        },
+
+        // Prepare a hash of attributes (or other model) to be added to this
+        // collection.
+        _prepareModel: function(attrs, options) {
+            if (this._isModel(attrs)) {
+                if (!attrs.collection) attrs.collection = this;
+                return attrs;
+            }
+            options = options ? _.clone(options) : {};
+            options.collection = this;
+            var model = new this.model(attrs, options);
+            if (!model.validationError) return model;
+            this.trigger('invalid', this, model.validationError, options);
+            return false;
+        },
+
+        // Method for checking whether an object should be considered a model for
+        // the purposes of adding to the collection.
+        _isModel: function (model) {
+            return model instanceof M;
+        },
+
+        // Internal method to create a model's ties to a collection.
+        _addReference: function(model, options) {
+            this._byId[model.cid] = model;
+            var id = this.modelId(model.attributes);
+            if (id != null) this._byId[id] = model;
+            model.on('all', this._onModelEvent, this);
+        },
+
+        // Internal method to sever a model's ties to a collection.
+        _removeReference: function(model, options) {
+            if (this === model.collection) delete model.collection;
+            model.off('all', this._onModelEvent, this);
+        },
+
+        // Internal method called every time a model in the set fires an event.
+        // Sets need to update their indexes when models change ids. All other
+        // events simply proxy through. "add" and "remove" events that originate
+        // in other collections are ignored.
+        _onModelEvent: function(event, model, collection, options) {
+            if ((event === 'add' || event === 'remove') && collection !== this) return;
+            if (event === 'destroy') this.remove(model, options);
+            if (event === 'change') {
+                var prevId = this.modelId(model.previousAttributes());
+                var id = this.modelId(model.attributes);
+                if (prevId !== id) {
+                    if (prevId != null) delete this._byId[prevId];
+                    if (id != null) this._byId[id] = model;
+                }
+            }
+            this.trigger.apply(this, arguments);
+        }
+
+    });
+
+    // Underscore methods that we want to implement on the Collection.
+    // 90% of the core usefulness of BI Collections is actually implemented
+    // right here:
+    var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
+        'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
+        'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
+        'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
+        'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
+        'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition'];
+
+    // Mix in each Underscore method as a proxy to `Collection#models`.
+    _.each(methods, function(method) {
+        if (!_[method]) return;
+        Collection.prototype[method] = function() {
+            var args = slice.call(arguments);
+            args.unshift(this.models);
+            return _[method].apply(_, args);
+        };
+    });
+
+    // Underscore methods that take a property name as an argument.
+    var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
+
+    // Use attributes instead of properties.
+    _.each(attributeMethods, function(method) {
+        if (!_[method]) return;
+        Collection.prototype[method] = function(value, context) {
+            var iterator = _.isFunction(value) ? value : function(model) {
+                return model.get(value);
+            };
+            return _[method](this.models, iterator, context);
+        };
+    });
+
+    // BI.V
+    // -------------
+
+    // BI Views are almost more convention than they are actual code. A V
+    // is simply a JavaScript object that represents a logical chunk of UI in the
+    // DOM. This might be a single item, an entire list, a sidebar or panel, or
+    // even the surrounding frame which wraps your whole app. Defining a chunk of
+    // UI as a **V** allows you to define your DOM events declaratively, without
+    // having to worry about render order ... and makes it easy for the view to
+    // react to specific changes in the state of your models.
+
+    // Creating a BI.V creates its initial element outside of the DOM,
+    // if an existing element is not provided...
+    var V = BI.V = function(options) {
+        this.cid = _.uniqueId('view');
+        options = options || {};
+        this.options = _.defaults(options, _.result(this, '_defaultConfig'));
+        _.extend(this, _.pick(this.options, viewOptions));
+        this._ensureElement();
+        this._init.apply(this, arguments);
+    };
+
+    // Cached regex to split keys for `delegate`.
+    var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+
+    // List of view options to be merged as properties.
+    var viewOptions = ['rootURL', 'model', 'parent', 'collection', 'element', 'id', 'attributes', 'baseCls', 'tagName', 'events'];
+
+    // Set up all inheritable **BI.V** properties and methods.
+    _.extend(V.prototype, Events, {
+
+        // The default `tagName` of a V's element is `"div"`.
+        tagName: 'div',
+
+        // jQuery 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);
+        },
+
+        _defaultConfig: function(){return {}},
+
+        // _init is an empty function by default. Override it with your own
+        // initialization logic.
+        _init: function(){},
+
+        //容器,默认放在this.element上
+        _vessel: function(){return this.element},
+        // **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(vessel) {
+            return this;
+        },
+
+        // Remove this view by taking the element out of the DOM, and removing any
+        // applicable BI.Events listeners.
+        remove: function() {
+            this._removeElement();
+            this.stopListening();
+            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();
+            if ($.browser.msie === true) {
+                this.el.outerHTML = '';
+            }
+        },
+
+        // 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.$vessel = this._vessel();
+            this._render(this.$vessel);
+            this.delegateEvents();
+            return this;
+        },
+
+        setVisible: function(visible){
+            this.options.invisible = !visible;
+            if (visible){
+                this.element.show();
+            } else {
+                this.element.hide();
+            }
+        },
+
+        isVisible: function(){
+            return !this.options.invisible;
+        },
+
+        visible: function(){
+            this.setVisible(true);
+        },
+
+        invisible: function(){
+            this.setVisible(false);
+        },
+
+        // 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 = el instanceof BI.$ ? el : BI.$(el);
+            this.element = this.$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) {
+            if (!(events || (events = _.result(this, 'events')))) return this;
+            this.undelegateEvents();
+            for (var key in events) {
+                var method = events[key];
+                if (!_.isFunction(method)) method = this[events[key]];
+                if (!method) continue;
+                var match = key.match(delegateEventSplitter);
+                this.delegate(match[1], match[2], _.bind(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.$vessel.on(eventName + '.delegateEvents' + this.cid, selector, listener);
+        },
+
+        // 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
+        // BI views attached to the same DOM element.
+        undelegateEvents: function() {
+            if (this.$vessel) this.$vessel.off('.delegateEvents' + this.cid);
+            return this;
+        },
+
+        // A finer-grained `undelegateEvents` for removing a single delegated event.
+        // `selector` and `listener` are both optional.
+        undelegate: function(eventName, selector, listener) {
+            this.$vessel.off(eventName + '.delegateEvents' + this.cid, selector, listener);
+        },
+
+        // Produces a DOM element to be assigned to your view. Exposed for
+        // subclasses using an alternative DOM manipulation API.
+        _createElement: function(tagName) {
+            return document.createElement(tagName);
+        },
+
+        // Ensure that the V 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() {
+            var attrs = _.extend({}, _.result(this, 'attributes'));
+            if (this.baseCls) attrs['class'] = _.result(this, 'baseCls');
+            if (!this.element) {
+                this.setElement(this._createElement(_.result(this, 'tagName')));
+            } else {
+                this.setElement(_.result(this, 'element'));
+            }
+            this._setAttributes(attrs);
+        },
+
+        // 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);
+        }
+
+    });
+
+    // BI.sync
+    // -------------
+
+    // Override this function to change the manner in which BI persists
+    // models to the server. You will be passed the type of request, and the
+    // model in question. By default, makes a RESTful Ajax request
+    // to the model's `url()`. Some possible customizations could be:
+    //
+    // * Use `setTimeout` to batch rapid-fire updates into a single request.
+    // * Send up the models as XML instead of JSON.
+    // * Persist models via WebSockets instead of Ajax.
+    //
+    // Turn on `BI.emulateHTTP` in order to send `PUT` and `DELETE` requests
+    // as `POST`, with a `_method` parameter containing the true HTTP method,
+    // as well as all requests with the body as `application/x-www-form-urlencoded`
+    // instead of `application/json` with the model in a param named `model`.
+    // Useful when interfacing with server-side languages like **PHP** that make
+    // it difficult to read the body of `PUT` requests.
+    BI.sync = function(method, model, options) {
+        var type = methodMap[method];
+
+        // Default options, unless specified.
+        _.defaults(options || (options = {}), {
+            emulateHTTP: BI.emulateHTTP,
+            emulateJSON: BI.emulateJSON
+        });
+
+        // Default JSON-request options.
+        var params = {type: type, dataType: 'json'};
+
+        // Ensure that we have a URL.
+        if (!options.url) {
+            params.url = _.result(model, method+"URL") || _.result(model, 'url');
+            if(!params.url){
+                return;
+            }
+        }
+
+        // Ensure that we have the appropriate request data.
+        if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
+            params.contentType = 'application/json';
+            params.data = _.extend({id: model.id}, model.toJSON(options), options.attrs);
+        }
+
+        // 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 = options.data ? options.data : 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.apply(this, arguments);
+        };
+
+        // Make the request, allowing the user to override any Ajax options.
+        var xhr = options.xhr = BI.ajax(_.extend(params, options));
+        model.trigger('request', xhr, model, options);
+        return xhr;
+    };
+
+    // Map from CRUD to HTTP for our default `BI.sync` implementation.
+    var methodMap = {
+        'create': 'POST',
+        'update': 'PUT',
+        'patch':  'PATCH',
+        'delete': 'DELETE',
+        'read':   'GET'
+    };
+
+    // Set the default implementation of `BI.ajax` to proxy through to `$`.
+    // Override this if you'd like to use a different library.
+    BI.ajax = $.ajax;
+
+    // BI.Router
+    // ---------------
+
+    // Routers map faux-URLs to actions, and fire events when routes are
+    // matched. Creating a new one sets its `routes` hash, if not set statically.
+    var Router = BI.Router = function(options) {
+        options || (options = {});
+        if (options.routes) this.routes = options.routes;
+        this._bindRoutes();
+        this._init.apply(this, arguments);
+    };
+
+    // Cached regular expressions for matching named param parts and splatted
+    // parts of route strings.
+    var optionalParam = /\((.*?)\)/g;
+    var namedParam    = /(\(\?)?:\w+/g;
+    var splatParam    = /\*\w+/g;
+    var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
+
+    // Set up all inheritable **BI.Router** properties and methods.
+    _.extend(Router.prototype, Events, {
+
+        // _init is an empty function by default. Override it with your own
+        // initialization logic.
+        _init: function(){},
+
+        // Manually bind a single named route to a callback. For example:
+        //
+        //     this.route('search/:query/p:num', 'search', function(query, num) {
+        //       ...
+        //     });
+        //
+        route: function(route, name, callback) {
+            if (!_.isRegExp(route)) route = this._routeToRegExp(route);
+            if (_.isFunction(name)) {
+                callback = name;
+                name = '';
+            }
+            if (!callback) callback = this[name];
+            var router = this;
+            BI.history.route(route, function(fragment) {
+                var args = router._extractParameters(route, fragment);
+                if (router.execute(callback, args, name) !== false) {
+                    router.trigger.apply(router, ['route:' + name].concat(args));
+                    router.trigger('route', name, args);
+                    BI.history.trigger('route', router, name, args);
+                }
+            });
+            return this;
+        },
+
+        // Execute a route handler with the provided parameters.  This is an
+        // excellent place to do pre-route setup or post-route cleanup.
+        execute: function(callback, args, name) {
+            if (callback) callback.apply(this, args);
+        },
+
+        // Simple proxy to `BI.history` to save a fragment into the history.
+        navigate: function(fragment, options) {
+            BI.history.navigate(fragment, options);
+            return this;
+        },
+
+        // Bind all defined routes to `BI.history`. We have to reverse the
+        // order of the routes here to support behavior where the most general
+        // routes can be defined at the bottom of the route map.
+        _bindRoutes: function() {
+            if (!this.routes) return;
+            this.routes = _.result(this, 'routes');
+            var route, routes = _.keys(this.routes);
+            while ((route = routes.pop()) != null) {
+                this.route(route, this.routes[route]);
+            }
+        },
+
+        // Convert a route string into a regular expression, suitable for matching
+        // against the current location hash.
+        _routeToRegExp: function(route) {
+            route = route.replace(escapeRegExp, '\\$&')
+                .replace(optionalParam, '(?:$1)?')
+                .replace(namedParam, function(match, optional) {
+                    return optional ? match : '([^/?]+)';
+                })
+                .replace(splatParam, '([^?]*?)');
+            return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
+        },
+
+        // Given a route, and a URL fragment that it matches, return the array of
+        // extracted decoded parameters. Empty or unmatched parameters will be
+        // treated as `null` to normalize cross-browser behavior.
+        _extractParameters: function(route, fragment) {
+            var params = route.exec(fragment).slice(1);
+            return _.map(params, function(param, i) {
+                // Don't decode the search params.
+                if (i === params.length - 1) return param || null;
+                return param ? decodeURIComponent(param) : null;
+            });
+        }
+
+    });
+
+    // BI.History
+    // ----------------
+
+    // Handles cross-browser history management, based on either
+    // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
+    // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
+    // and URL fragments. If the browser supports neither (old IE, natch),
+    // falls back to polling.
+    var History = BI.History = function() {
+        this.handlers = [];
+        _.bindAll(this, 'checkUrl');
+
+        // Ensure that `History` can be used outside of the browser.
+        if (typeof window !== 'undefined') {
+            this.location = window.location;
+            this.history = window.history;
+        }
+    };
+
+    // Cached regex for stripping a leading hash/slash and trailing space.
+    var routeStripper = /^[#\/]|\s+$/g;
+
+    // Cached regex for stripping leading and trailing slashes.
+    var rootStripper = /^\/+|\/+$/g;
+
+    // Cached regex for stripping urls of hash.
+    var pathStripper = /#.*$/;
+
+    // Has the history handling already been started?
+    History.started = false;
+
+    // Set up all inheritable **BI.History** properties and methods.
+    _.extend(History.prototype, Events, {
+
+        // The default interval to poll for hash changes, if necessary, is
+        // twenty times a second.
+        interval: 50,
+
+        // Are we at the app root?
+        atRoot: function() {
+            var path = this.location.pathname.replace(/[^\/]$/, '$&/');
+            return path === this.root && !this.getSearch();
+        },
+
+        // In IE6, the hash fragment and search params are incorrect if the
+        // fragment contains `?`.
+        getSearch: function() {
+            var match = this.location.href.replace(/#.*/, '').match(/\?.+/);
+            return match ? match[0] : '';
+        },
+
+        // Gets the true hash value. Cannot use location.hash directly due to bug
+        // in Firefox where location.hash will always be decoded.
+        getHash: function(window) {
+            var match = (window || this).location.href.match(/#(.*)$/);
+            return match ? match[1] : '';
+        },
+
+        // Get the pathname and search params, without the root.
+        getPath: function() {
+            var path = decodeURI(this.location.pathname + this.getSearch());
+            var root = this.root.slice(0, -1);
+            if (!path.indexOf(root)) path = path.slice(root.length);
+            return path.charAt(0) === '/' ? path.slice(1) : path;
+        },
+
+        // Get the cross-browser normalized URL fragment from the path or hash.
+        getFragment: function(fragment) {
+            if (fragment == null) {
+                if (this._hasPushState || !this._wantsHashChange) {
+                    fragment = this.getPath();
+                } else {
+                    fragment = this.getHash();
+                }
+            }
+            return fragment.replace(routeStripper, '');
+        },
+
+        // Start the hash change handling, returning `true` if the current URL matches
+        // an existing route, and `false` otherwise.
+        start: function(options) {
+            if (History.started) throw new Error('BI.history has already been started');
+            History.started = true;
+
+            // Figure out the initial configuration. Do we need an iframe?
+            // Is pushState desired ... is it available?
+            this.options          = _.extend({root: '/'}, this.options, options);
+            this.root             = this.options.root;
+            this._wantsHashChange = this.options.hashChange !== false;
+            this._hasHashChange   = 'onhashchange' in window;
+            this._wantsPushState  = !!this.options.pushState;
+            this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
+            this.fragment         = this.getFragment();
+
+            // Normalize root to always include a leading and trailing slash.
+            this.root = ('/' + this.root + '/').replace(rootStripper, '/');
+
+            // Transition from hashChange to pushState or vice versa if both are
+            // requested.
+            if (this._wantsHashChange && this._wantsPushState) {
+
+                // If we've started off with a route from a `pushState`-enabled
+                // browser, but we're currently in a browser that doesn't support it...
+                if (!this._hasPushState && !this.atRoot()) {
+                    var root = this.root.slice(0, -1) || '/';
+                    this.location.replace(root + '#' + this.getPath());
+                    // Return immediately as browser will do redirect to new url
+                    return true;
+
+                    // Or if we've started out with a hash-based route, but we're currently
+                    // in a browser where it could be `pushState`-based instead...
+                } else if (this._hasPushState && this.atRoot()) {
+                    this.navigate(this.getHash(), {replace: true});
+                }
+
+            }
+
+            // Proxy an iframe to handle location events if the browser doesn't
+            // support the `hashchange` event, HTML5 history, or the user wants
+            // `hashChange` but not `pushState`.
+            if (!this._hasHashChange && this._wantsHashChange && (!this._wantsPushState || !this._hasPushState)) {
+                var iframe = document.createElement('iframe');
+                iframe.src = 'javascript:0';
+                iframe.style.display = 'none';
+                iframe.tabIndex = -1;
+                var body = document.body;
+                // Using `appendChild` will throw on IE < 9 if the document is not ready.
+                this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow;
+                this.iframe.document.open().close();
+                this.iframe.location.hash = '#' + this.fragment;
+            }
+
+            // Add a cross-platform `addEventListener` shim for older browsers.
+            var addEventListener = window.addEventListener || function (eventName, listener) {
+                return attachEvent('on' + eventName, listener);
+            };
+
+            // Depending on whether we're using pushState or hashes, and whether
+            // 'onhashchange' is supported, determine how we check the URL state.
+            if (this._hasPushState) {
+                addEventListener('popstate', this.checkUrl, false);
+            } else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
+                addEventListener('hashchange', this.checkUrl, false);
+            } else if (this._wantsHashChange) {
+                this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
+            }
+
+            if (!this.options.silent) return this.loadUrl();
+        },
+
+        // Disable BI.history, perhaps temporarily. Not useful in a real app,
+        // but possibly useful for unit testing Routers.
+        stop: function() {
+            // Add a cross-platform `removeEventListener` shim for older browsers.
+            var removeEventListener = window.removeEventListener || function (eventName, listener) {
+                return detachEvent('on' + eventName, listener);
+            };
+
+            // Remove window listeners.
+            if (this._hasPushState) {
+                removeEventListener('popstate', this.checkUrl, false);
+            } else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
+                removeEventListener('hashchange', this.checkUrl, false);
+            }
+
+            // Clean up the iframe if necessary.
+            if (this.iframe) {
+                document.body.removeChild(this.iframe.frameElement);
+                this.iframe = null;
+            }
+
+            // Some environments will throw when clearing an undefined interval.
+            if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
+            History.started = false;
+        },
+
+        // Add a route to be tested when the fragment changes. Routes added later
+        // may override previous routes.
+        route: function(route, callback) {
+            this.handlers.unshift({route: route, callback: callback});
+        },
+
+        // Checks the current URL to see if it has changed, and if it has,
+        // calls `loadUrl`, normalizing across the hidden iframe.
+        checkUrl: function(e) {
+            var current = this.getFragment();
+
+            // If the user pressed the back button, the iframe's hash will have
+            // changed and we should use that for comparison.
+            if (current === this.fragment && this.iframe) {
+                current = this.getHash(this.iframe);
+            }
+
+            if (current === this.fragment) return false;
+            if (this.iframe) this.navigate(current);
+            this.loadUrl();
+        },
+
+        // Attempt to load the current URL fragment. If a route succeeds with a
+        // match, returns `true`. If no defined routes matches the fragment,
+        // returns `false`.
+        loadUrl: function(fragment) {
+            fragment = this.fragment = this.getFragment(fragment);
+            return _.any(this.handlers, function(handler) {
+                if (handler.route.test(fragment)) {
+                    handler.callback(fragment);
+                    return true;
+                }
+            });
+        },
+
+        // Save a fragment into the hash history, or replace the URL state if the
+        // 'replace' option is passed. You are responsible for properly URL-encoding
+        // the fragment in advance.
+        //
+        // The options object can contain `trigger: true` if you wish to have the
+        // route callback be fired (not usually desirable), or `replace: true`, if
+        // you wish to modify the current URL without adding an entry to the history.
+        navigate: function(fragment, options) {
+            if (!History.started) return false;
+            if (!options || options === true) options = {trigger: !!options};
+
+            // Normalize the fragment.
+            fragment = this.getFragment(fragment || '');
+
+            // Don't include a trailing slash on the root.
+            var root = this.root;
+            if (fragment === '' || fragment.charAt(0) === '?') {
+                root = root.slice(0, -1) || '/';
+            }
+            var url = root + fragment;
+
+            // Strip the hash and decode for matching.
+            fragment = decodeURI(fragment.replace(pathStripper, ''));
+
+            if (this.fragment === fragment) return;
+            this.fragment = fragment;
+
+            // If pushState is available, we use it to set the fragment as a real URL.
+            if (this._hasPushState) {
+                this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
+
+                // If hash changes haven't been explicitly disabled, update the hash
+                // fragment to store history.
+            } else if (this._wantsHashChange) {
+                this._updateHash(this.location, fragment, options.replace);
+                if (this.iframe && (fragment !== this.getHash(this.iframe))) {
+                    // Opening and closing the iframe tricks IE7 and earlier to push a
+                    // history entry on hash-tag change.  When replace is true, we don't
+                    // want this.
+                    if (!options.replace) this.iframe.document.open().close();
+                    this._updateHash(this.iframe.location, fragment, options.replace);
+                }
+
+                // If you've told us that you explicitly don't want fallback hashchange-
+                // based history, then `navigate` becomes a page refresh.
+            } else {
+                return this.location.assign(url);
+            }
+            if (options.trigger) return this.loadUrl(fragment);
+        },
+
+        // Update the hash location, either replacing the current entry, or adding
+        // a new one to the browser history.
+        _updateHash: function(location, fragment, replace) {
+            if (replace) {
+                var href = location.href.replace(/(javascript:|#).*$/, '');
+                location.replace(href + '#' + fragment);
+            } else {
+                // Some browsers require that `hash` contains a leading #.
+                location.hash = '#' + fragment;
+            }
+        }
+
+    });
+
+    // Create the default BI.history.
+    BI.history = new History;
+
+    // Helpers
+    // -------
+
+    // Helper function to correctly set up the prototype chain, for subclasses.
+    // Similar to `goog.inherits`, but uses a hash of prototype properties and
+    // class properties to be extended.
+    var extend = function(protoProps, staticProps) {
+        var parent = this;
+        var child;
+
+        // The constructor function for the new subclass is either defined by you
+        // (the "constructor" property in your `extend` definition), or defaulted
+        // by us to simply call the parent's constructor.
+        if (protoProps && _.has(protoProps, 'constructor')) {
+            child = protoProps.constructor;
+        } else {
+            child = function(){ return parent.apply(this, arguments); };
+        }
+
+        // Add static properties to the constructor function, if supplied.
+        _.extend(child, parent, staticProps);
+
+        // Set the prototype chain to inherit from `parent`, without calling
+        // `parent`'s constructor function.
+        var Surrogate = function(){ this.constructor = child; };
+        Surrogate.prototype = parent.prototype;
+        child.prototype = new Surrogate;
+
+        // Add prototype properties (instance properties) to the subclass,
+        // if supplied.
+        if (protoProps) _.extend(child.prototype, protoProps);
+
+        // Set a convenience property in case the parent's prototype is needed
+        // later.
+        child.__super__ = parent.prototype;
+
+        return child;
+    };
+
+    // Set up inheritance for the model, collection, router, view and history.
+    M.extend = Collection.extend = Router.extend = V.extend = History.extend = extend;
+
+    // Throw an error when a URL is needed, and none is supplied.
+    var urlError = function() {
+        throw new Error('A "url" property or function must be specified');
+    };
+
+    // Wrap an optional error callback with a fallback error event.
+    var wrapError = function(model, options) {
+        var error = options.error;
+        options.error = function(resp) {
+            if (error) error(model, resp, options);
+            model.trigger('error', model, resp, options);
+        };
+    };
+
+    return BI;
+
+}));/**
+ * MVC路由
+ * @class BI.WRouter
+ * @extends BI.Router
+ * @type {*|void|Object}
+ */
+BI.WRouter = BI.Router.extend({
+    add: function(route, callback){
+        this.handlers || (this.handlers=[]);
+        this.handlers.unshift({route: route, callback: callback})
+    },
+
+    route: function(route, name, callback) {
+        if (!_.isRegExp(route)) route = this._routeToRegExp(route);
+        if (_.isFunction(name)) {
+            callback = name;
+            name = '';
+        }
+        if (!callback) callback = this[name];
+        var self = this;
+        this.add(route, function(fragment) {
+            var args = self._extractParameters(route, fragment);
+            var result = self.execute(callback, args, name)
+            if (result !== false) {
+                self.trigger.apply(self, ['route:' + name].concat(args));
+                self.trigger('route', name, args);
+            }
+            return result;
+        });
+        return this;
+    },
+
+    execute: function(callback, args, name) {
+        if (callback) return callback.apply(this, args);
+        return name;
+    },
+
+    get: function(fragment){
+        var result = null;
+        _.any(this.handlers, function(handler) {
+            if (handler.route.test(fragment)) {
+                result = handler.callback(fragment);
+                return true;
+            }
+        });
+        return result;
+    }
+});/**
+ * 基本函数
+ * Create By GUY 2014\11\17
+ *
+ */
+
+if (!window.BI) {
+    window.BI = {};
+}
+;
+!(function ($, undefined) {
+    _.extend(BI, {
+        version: "4.0"
+    });
+    var traverse = function (func, context) {
+        return function (value, key, obj) {
+            return func.call(context, key, value, obj);
+        }
+    };
+    var _apply = function (name) {
+        return function () {
+            return _[name].apply(_, arguments);
+        }
+    };
+    var _applyFunc = function (name) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments, 0);
+            args[1] = _.isFunction(args[1]) ? traverse(args[1], args[2]) : args[1];
+            return _[name].apply(_, args);
+        }
+    };
+
+    //Utility
+    _.extend(BI, {
+        i18nText: function (key) {
+            var localeText = key;
+            if (!localeText) {
+                localeText = key;
+            }
+            var len = arguments.length;
+            if (len > 1) {
+                for (var i = 1; i < len; i++) {
+                    var key = "{R" + i + "}";
+                    localeText = localeText.replaceAll(key, arguments[i] + "");
+                }
+            }
+            return localeText;
+        },
+
+        assert: function (v, is) {
+            if (this.isFunction(is)) {
+                if (!is(v)) {
+                    throw new Error(v + "值不合法");
+                } else {
+                    return true;
+                }
+            }
+            if (!this.isArray(is)) {
+                is = [is];
+            }
+            if (!this.deepContains(is, v)) {
+                throw new Error(v + "值不合法");
+            }
+        },
+
+        warn: function (message) {
+            console.warn(message)
+        },
+
+        UUID: function () {
+            var f = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+            var str = "";
+            for (var i = 0; i < 16; i++) {
+                var r = parseInt(f.length * Math.random(), 10);
+                str += f[r];
+            }
+            return str;
+        },
+
+        isWidget: function (widget) {
+            return widget instanceof BI.Widget || (BI.View && widget instanceof BI.View);
+        },
+
+        createWidgets: function (items, options) {
+            if (!BI.isArray(items)) {
+                throw new Error("无法根据items创建组件?")
+            }
+            return BI.map(BI.flatten(items), function (i, item) {
+                return BI.createWidget(item, BI.deepClone(options));
+            });
+        },
+
+        createItems: function (data, innerAttr, outerAttr) {
+            innerAttr = BI.isArray(innerAttr) ? innerAttr : BI.makeArray(BI.flatten(data).length, innerAttr);
+            outerAttr = BI.isArray(outerAttr) ? outerAttr : BI.makeArray(BI.flatten(data).length, outerAttr);
+            return BI.map(data, function (i, item) {
+                if (BI.isArray(item)) {
+                    return BI.createItems(item, innerAttr, outerAttr);
+                }
+                if (item instanceof BI.Widget) {
+                    return BI.extend({}, innerAttr.shift(), outerAttr.shift(), {
+                        type: null,
+                        el: item
+                    });
+                }
+                if (innerAttr[0] instanceof BI.Widget) {
+                    outerAttr.shift();
+                    return BI.extend({}, item, {
+                        el: innerAttr.shift()
+                    })
+                }
+                if (item.el instanceof BI.Widget || (BI.View && item.el instanceof BI.View)) {
+                    innerAttr.shift();
+                    return BI.extend({}, outerAttr.shift(), {type: null}, item);
+                }
+                if (item.el) {
+                    return BI.extend({}, outerAttr.shift(), item, {
+                        el: BI.extend({}, innerAttr.shift(), item.el)
+                    })
+                }
+                return BI.extend({}, outerAttr.shift(), {
+                    el: BI.extend({}, innerAttr.shift(), item)
+                })
+            })
+        },
+
+        //用容器包装items
+        packageItems: function (items, layouts) {
+            for (var i = layouts.length - 1; i >= 0; i--) {
+                items = BI.map(items, function (k, it) {
+                    return BI.extend({}, layouts[i], {
+                        items: [
+                            BI.extend({}, layouts[i].el, {
+                                el: it
+                            })
+                        ]
+                    })
+                })
+            }
+            return items;
+        },
+
+        formatEL: function (obj) {
+            if (obj && obj.el) {
+                return obj;
+            }
+            return {
+                el: obj
+            };
+        },
+
+        //剥开EL
+        stripEL: function (obj) {
+            return obj.type && obj || obj.el || obj;
+        },
+
+        trans2Element: function (widgets) {
+            return BI.map(widgets, function (i, wi) {
+                return wi.element;
+            });
+        }
+    });
+
+    //集合相关方法
+    _.each(["where", "findWhere", "contains", "invoke", "pluck", "shuffle", "sample", "toArray", "size"], function (name) {
+        BI[name] = _apply(name)
+    });
+    _.each(["each", "map", "reduce", "reduceRight", "find", "filter", "reject", "every", "all", "some", "any", "max", "min",
+        "sortBy", "groupBy", "indexBy", "countBy", "partition"], function (name) {
+        BI[name] = _applyFunc(name)
+    });
+    _.extend(BI, {
+        clamp: function (value, minValue, maxValue) {
+            if (value < minValue) {
+                value = minValue;
+            }
+            if (value > maxValue) {
+                value = maxValue;
+            }
+            return value;
+        },
+        //数数
+        count: function (from, to, predicate) {
+            var t;
+            if (predicate) {
+                for (t = from; t < to; t++) {
+                    predicate(t);
+                }
+            }
+            return to - from;
+        },
+
+        //倒数
+        inverse: function (from, to, predicate) {
+            return BI.count(to, from, predicate);
+        },
+
+        firstKey: function (obj) {
+            var res = undefined;
+            BI.any(obj, function (key, value) {
+                res = key;
+                return true;
+            });
+            return res;
+        },
+
+        lastKey: function (obj) {
+            var res = undefined;
+            BI.each(obj, function (key, value) {
+                res = key;
+                return true;
+            });
+            return res;
+        },
+
+        firstObject: function (obj) {
+            var res = undefined;
+            BI.any(obj, function (key, value) {
+                res = value;
+                return true;
+            });
+            return res;
+        },
+
+        lastObject: function (obj) {
+            var res = undefined;
+            BI.each(obj, function (key, value) {
+                res = value;
+                return true;
+            });
+            return res;
+        },
+
+        concat: function (obj1, obj2) {
+            if (BI.isKey(obj1)) {
+                return obj1 + "" + obj2;
+            }
+            if (BI.isArray(obj1)) {
+                return obj1.concat(obj2);
+            }
+            if (BI.isObject(obj1)) {
+                return _.extend({}, obj1, obj2);
+            }
+        },
+
+        backEach: function (obj, predicate, context) {
+            predicate = BI.iteratee(predicate, context);
+            for (var index = obj.length - 1; index >= 0; index--) {
+                predicate(index, obj[index], obj);
+            }
+            return false;
+        },
+
+        backAny: function (obj, predicate, context) {
+            predicate = BI.iteratee(predicate, context);
+            for (var index = obj.length - 1; index >= 0; index--) {
+                if (predicate(index, obj[index], obj)) return true;
+            }
+            return false;
+        },
+
+        backEvery: function (obj, predicate, context) {
+            predicate = BI.iteratee(predicate, context);
+            for (var index = obj.length - 1; index >= 0; index--) {
+                if (!predicate(index, obj[index], obj)) return false;
+            }
+            return true;
+        },
+
+        remove: function (obj, target, context) {
+            var isFunction = BI.isFunction(target);
+            target = isFunction || BI.isArray(target) ? target : [target];
+            var i;
+            if (BI.isArray(obj)) {
+                for (i = 0; i < obj.length; i++) {
+                    if ((isFunction && target.apply(context, [i, obj[i]]) === true) || (!isFunction && target.contains(obj[i]))) {
+                        obj.splice(i--, 1);
+                    }
+                }
+            } else {
+                BI.each(obj, function (i, v) {
+                    if ((isFunction && target.apply(context, [i, obj[i]]) === true) || (!isFunction && target.contains(obj[i]))) {
+                        delete obj[i];
+                    }
+                });
+            }
+        },
+
+        removeAt: function (obj, index) {
+            index = BI.isArray(index) ? index : [index];
+            var isArray = BI.isArray(obj), i;
+            for (i = 0; i < index.length; i++) {
+                if (isArray) {
+                    obj[index[i]] = "$deleteIndex";
+                } else {
+                    delete obj[index[i]];
+                }
+            }
+            if (isArray) {
+                BI.remove(obj, "$deleteIndex");
+            }
+        },
+
+        string2Array: function (str) {
+            return str.split('&-&');
+        },
+
+        array2String: function (array) {
+            return array.join("&-&");
+        },
+
+        abc2Int: function (str) {
+            var idx = 0, start = 'A', str = str.toUpperCase();
+            for (var i = 0, len = str.length; i < len; ++i) {
+                idx = str.charAt(i).charCodeAt(0) - start.charCodeAt(0) + 26 * idx + 1;
+                if (idx > (2147483646 - str.charAt(i).charCodeAt(0) + start.charCodeAt(0)) / 26) {
+                    return 0;
+                }
+            }
+            return idx;
+        },
+
+        int2Abc: function (num) {
+            var DIGITS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
+            var idx = num, str = "";
+            if (num === 0) {
+                return "";
+            }
+            while (idx !== 0) {
+                var t = idx % 26;
+                if (t === 0) {
+                    t = 26;
+                }
+                str = DIGITS[t - 1] + str;
+                idx = (idx - t) / 26;
+            }
+            return str;
+        }
+    });
+
+    //数组相关的方法
+    _.each(["first", "initial", "last", "rest", "compact", "flatten", "without", "union", "intersection",
+        "difference", "zip", "unzip", "object", "indexOf", "lastIndexOf", "sortedIndex", "range"], function (name) {
+        BI[name] = _apply(name)
+    });
+    _.each(["findIndex", "findLastIndex"], function (name) {
+        BI[name] = _applyFunc(name)
+    });
+    _.extend(BI, {
+        //构建一个长度为length的数组
+        makeArray: function (length, value) {
+            var res = [];
+            for (var i = 0; i < length; i++) {
+                if (BI.isNull(value)) {
+                    res.push(i);
+                } else {
+                    res.push(BI.deepClone(value));
+                }
+            }
+            return res;
+        },
+
+        makeObject: function (array, value) {
+            var map = {};
+            for (var i = 0; i < array.length; i++) {
+                if (BI.isNull(value)) {
+                    map[array[i]] = array[i];
+                } else {
+                    map[array[i]] = BI.deepClone(value);
+                }
+            }
+            return map;
+        },
+
+        makeArrayByArray: function (array, value) {
+            var res = [];
+            if (!array) {
+                return res;
+            }
+            for (var i = 0, len = array.length; i < len; i++) {
+                if (BI.isArray(array[i])) {
+                    res.push(arguments.callee(array[i], value));
+                } else {
+                    res.push(BI.deepClone(value));
+                }
+            }
+            return res;
+        },
+
+        uniq: function (array, isSorted, iteratee, context) {
+            if (array == null) return [];
+            if (!_.isBoolean(isSorted)) {
+                context = iteratee;
+                iteratee = isSorted;
+                isSorted = false;
+            }
+            iteratee && (iteratee = traverse(iteratee, context));
+            return _.uniq.call(_, array, isSorted, iteratee, context);
+        }
+    });
+
+    //对象相关方法
+    _.each(["keys", "allKeys", "values", "pairs", "invert", "create", "functions", "extend", "extendOwn",
+        "defaults", "clone", "property", "propertyOf", "matcher", "isEqual", "isMatch", "isEmpty",
+        "isElement", "isNumber", "isString", "isArray", "isObject", "isArguments", "isFunction", "isFinite",
+        "isBoolean", "isDate", "isRegExp", "isError", "isNaN", "isUndefined"], function (name) {
+        BI[name] = _apply(name)
+    });
+    _.each(["mapObject", "findKey", "pick", "omit", "tap"], function (name) {
+        BI[name] = _applyFunc(name)
+    });
+    _.extend(BI, {
+
+        inherit: function (sb, sp, overrides) {
+            if (typeof sp == 'object') {
+                overrides = sp;
+                sp = sb;
+                sb = function () {
+                    sp.apply(this, arguments);
+                };
+            }
+            var F = function () {
+            }, spp = sp.prototype;
+            F.prototype = spp;
+            sb.prototype = new F();
+            sb.superclass = spp;
+            _.extend(sb.prototype, overrides, {
+                superclass: sp
+            });
+            return sb;
+        },
+
+        has: function (obj, keys) {
+            if (BI.isKey(keys)) {
+                return _.has.apply(_, arguments);
+            }
+            if (!keys || BI.isEmpty(keys)) {
+                return false;
+            }
+            return BI.every(keys, function (i, key) {
+                return _.has(obj, key);
+            });
+        },
+
+        //数字和字符串可以作为key
+        isKey: function (key) {
+            return BI.isNumber(key) || (BI.isString(key) && key.length > 0);
+        },
+
+        //忽略大小写的等于
+        isCapitalEqual: function (a, b) {
+            a = BI.isNull(a) ? a : ("" + a).toLowerCase();
+            b = BI.isNull(b) ? b : ("" + b).toLowerCase();
+            return BI.isEqual(a, b);
+        },
+
+        isWidthOrHeight: function (w) {
+            if (typeof w == 'number') {
+                return w >= 0;
+            } else if (typeof w == 'string') {
+                return /^\d{1,3}%$/.exec(w) || w == 'auto' || /^\d+px$/.exec(w);
+            }
+        },
+
+        isNotNull: function (obj) {
+            return !BI.isNull(obj);
+        },
+
+        isNull: function (obj) {
+            return typeof  obj === "undefined" || obj === null;
+        },
+
+        isPlainObject: function () {
+            return $.isPlainObject.apply($, arguments);
+        },
+
+        isEmptyArray: function (arr) {
+            return BI.isArray(arr) && BI.isEmpty(arr);
+        },
+
+        isNotEmptyArray: function (arr) {
+            return BI.isArray(arr) && !BI.isEmpty(arr);
+        },
+
+        isEmptyObject: function (obj) {
+            return BI.isEqual(obj, {});
+        },
+
+        isNotEmptyObject: function (obj) {
+            return BI.isPlainObject(obj) && !BI.isEmptyObject(obj);
+        },
+
+        isEmptyString: function (obj) {
+            return BI.isString(obj) && obj.length === 0;
+        },
+
+        isNotEmptyString: function (obj) {
+            return BI.isString(obj) && !BI.isEmptyString(obj);
+        },
+
+        isWindow: function () {
+            return $.isWindow.apply($, arguments);
+        }
+    });
+
+    //deep方法
+    _.extend(BI, {
+        /**
+         *完全克隆�?个js对象
+         * @param obj
+         * @returns {*}
+         */
+        deepClone: function (obj) {
+            if (obj === null || obj === undefined) {
+                return obj;
+            }
+
+            var type = Object.prototype.toString.call(obj);
+
+            // Date
+            if (type === '[object Date]') {
+                return new Date(obj.getTime());
+            }
+
+            var i, clone, key;
+
+            // Array
+            if (type === '[object Array]') {
+                i = obj.length;
+
+                clone = [];
+
+                while (i--) {
+                    clone[i] = BI.deepClone(obj[i]);
+                }
+            }
+            // Object
+            else if (type === '[object Object]' && obj.constructor === Object) {
+                clone = {};
+
+                for (var i in obj) {
+                    if (_.has(obj, i)) {
+                        clone[i] = BI.deepClone(obj[i]);
+                    }
+                }
+            }
+
+            return clone || obj;
+        },
+
+        isDeepMatch: function (object, attrs) {
+            var keys = BI.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 (!BI.isEqual(attrs[key], obj[key]) || !(key in obj)) return false;
+            }
+            return true;
+        },
+
+        deepContains: function (obj, copy) {
+            if (BI.isObject(copy)) {
+                return BI.any(obj, function (i, v) {
+                    if (BI.isEqual(v, copy)) {
+                        return true;
+                    }
+                })
+            }
+            return BI.contains(obj, copy);
+        },
+
+        deepIndexOf: function (obj, target) {
+            for (var i = 0; i < obj.length; i++) {
+                if (BI.isEqual(target, obj[i])) {
+                    return i;
+                }
+            }
+            return -1;
+        },
+
+        deepRemove: function (obj, target) {
+            var i;
+            if (BI.isArray(obj)) {
+                for (i = 0; i < obj.length; i++) {
+                    if (BI.isEqual(target, obj[i])) {
+                        obj.splice(i--, 1);
+                    }
+                }
+            } else {
+                BI.each(obj, function (i, v) {
+                    if (BI.isEqual(target, obj[i])) {
+                        delete obj[i];
+                    }
+                });
+            }
+        },
+
+        deepWithout: function (obj, target) {
+            if (BI.isArray(obj)) {
+                var result = [];
+                for (var i = 0; i < obj.length; i++) {
+                    if (!BI.isEqual(target, obj[i])) {
+                        result.push(obj[i]);
+                    }
+                }
+                return result;
+            } else {
+                var result = {};
+                BI.each(obj, function (i, v) {
+                    if (!BI.isEqual(target, obj[i])) {
+                        result[i] = v;
+                    }
+                });
+                return result;
+            }
+        },
+
+        deepUniq: function () {
+
+        },
+
+        //比较两个对象得出不一样的key值
+        deepDiff: function (object, other) {
+            object || (object = {});
+            other || (other = {});
+            var result = [];
+            var used = [];
+            for (var b in object) {
+                if (this.has(object, b)) {
+                    if (!this.isEqual(object[b], other[b])) {
+                        result.push(b);
+                    }
+                    used.push(b);
+                }
+            }
+            for (var b in other) {
+                if (this.has(other, b) && !used.contains(b)) {
+                    result.push(b);
+                }
+            }
+            return result;
+        }
+    });
+
+    //通用方法
+    _.each(["uniqueId", "result", "chain", "iteratee", "escape", "unescape"], function (name) {
+        BI[name] = function () {
+            return _[name].apply(_, arguments);
+        }
+    });
+
+    //事件相关方法
+    _.each(["bind", "once", "partial", "debounce", "throttle", "delay", "defer", "wrap"], function (name) {
+        BI[name] = function () {
+            return _[name].apply(_, arguments);
+        }
+    });
+
+    _.extend(BI, {
+        nextTick: (function () {
+            var callbacks = [];
+            var pending = false;
+            var timerFunc;
+
+            function nextTickHandler() {
+                pending = false;
+                var copies = callbacks.slice(0);
+                callbacks = [];
+                for (var i = 0; i < copies.length; i++) {
+                    copies[i].func.apply(null, copies[i].args);
+                }
+            }
+
+            /* istanbul ignore if */
+            if (typeof MutationObserver !== 'undefined') {
+                var counter = 1;
+                var observer = new MutationObserver(nextTickHandler);
+                var textNode = document.createTextNode(counter);
+                observer.observe(textNode, {
+                    characterData: true
+                });
+                timerFunc = function () {
+                    counter = (counter + 1) % 2;
+                    textNode.data = counter;
+                }
+            } else {
+                timerFunc = setTimeout
+            }
+            return function (cb) {
+                var args = [].slice.call(arguments, 1);
+                callbacks.push({func: cb, args: args});
+                if (pending) return;
+                pending = true;
+                timerFunc(nextTickHandler, 0);
+            }
+        })()
+    });
+
+    //数字相关方法
+    _.each(["random"], function (name) {
+        BI[name] = _apply(name)
+    });
+    _.extend(BI, {
+        getTime: function () {
+            if (window.performance && window.performance.now) {
+                return window.performance.now();
+            } else {
+                if (window.performance && window.performance.webkitNow) {
+                    return window.performance.webkitNow();
+                } else {
+                    if (Date.now) {
+                        return Date.now();
+                    } else {
+                        return new Date().getTime();
+                    }
+                }
+            }
+        },
+
+        parseInt: function (number) {
+            var radix = 10;
+            if (/^0x/g.test(number)) {
+                radix = 16;
+            }
+            try {
+                return parseInt(number, radix);
+            } catch (e) {
+                throw new Error("转成int类型失败");
+                return NaN;
+            }
+        },
+
+        parseFloat: function (number) {
+            try {
+                return parseFloat(number);
+            } catch (e) {
+                throw new Error("转成float类型失败");
+                return NaN;
+            }
+        },
+
+        isNaturalNumber: function (number) {
+            if (/^\d+$/.test(number)) {
+                return true;
+            }
+            return false;
+        },
+
+        isPositiveInteger: function (number) {
+            if (/^\+?[1-9][0-9]*$/.test(number)) {
+                return true;
+            }
+            return false;
+        },
+
+        isNegativeInteger: function (number) {
+            if (/^\-[1-9][0-9]*$/.test(number)) {
+                return true;
+            }
+            return false;
+        },
+
+        isInteger: function (number) {
+            if (/^\-?\d+$/.test(number)) {
+                return true;
+            }
+            return false;
+        },
+
+        isNumeric: function (number) {
+            return $.isNumeric(number);
+        },
+
+        isFloat: function (number) {
+            if (/^([+-]?)\\d*\\.\\d+$/.test(number)) {
+                return true;
+            }
+            return false;
+        },
+
+        isOdd: function (number) {
+            if (!BI.isInteger(number)) {
+                return false;
+            }
+            return number & 1 === 1;
+        },
+
+        isEven: function (number) {
+            if (!BI.isInteger(number)) {
+                return false;
+            }
+            return number & 1 === 0;
+        },
+
+        sum: function (array, iteratee, context) {
+            var sum = 0;
+            BI.each(array, function (i, item) {
+                if (iteratee) {
+                    sum += new Number(iteratee.apply(context, [i, item]));
+                } else {
+                    sum += new Number(item);
+                }
+            });
+            return sum;
+        },
+
+        average: function (array, iteratee, context) {
+            var sum = BI.sum(array, iteratee, context);
+            return sum / array.length;
+        }
+    });
+
+    //字符串相关方法
+    _.extend(BI, {
+        trim: function () {
+            return $.trim.apply($, arguments);
+        },
+
+        toUpperCase: function (string) {
+            return (string + "").toLocaleUpperCase();
+        },
+
+        toLowerCase: function (string) {
+            return (string + "").toLocaleLowerCase();
+        },
+
+        isLiteral: function (exp) {
+            var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/
+            return literalValueRE.test(exp)
+        },
+
+        stripQuotes: function (str) {
+            var a = str.charCodeAt(0)
+            var b = str.charCodeAt(str.length - 1)
+            return a === b && (a === 0x22 || a === 0x27)
+                ? str.slice(1, -1)
+                : str
+        },
+
+        //background-color => backgroundColor
+        camelize: function (str) {
+            return str.replace(/-(.)/g, function (_, character) {
+                return character.toUpperCase();
+            });
+        },
+
+        //backgroundColor => background-color
+        hyphenate: function (str) {
+            return str.replace(/([A-Z])/g, '-$1').toLowerCase();
+        },
+
+        isNotEmptyString: function (str) {
+            return BI.isString(str) && !BI.isEmpty(str);
+        },
+
+        isEmptyString: function (str) {
+            return BI.isString(str) && BI.isEmpty(str);
+        },
+
+        /**
+         * 对字符串进行加密 {@link #decrypt}
+         * @static
+         * @param str 原始字符�?
+         * @param keyt 密钥
+         * @returns {String} 加密后的字符�?
+         */
+        encrypt: function (str, keyt) {
+            if (str == "") {
+                return "";
+            }
+            str = escape(str);
+            if (!keyt || keyt == "") {
+                keyt = "655";
+            }
+            keyt = escape(keyt);
+            if (keyt == null || keyt.length <= 0) {
+                alert("Please enter a password with which to encrypt the message.");
+                return null;
+            }
+            var prand = "";
+            for (var i = 0; i < keyt.length; i++) {
+                prand += keyt.charCodeAt(i).toString();
+            }
+            var sPos = Math.floor(prand.length / 5);
+            var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
+
+            var incr = Math.ceil(keyt.length / 2);
+            var modu = Math.pow(2, 31) - 1;
+            if (mult < 2) {
+                alert("Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password.");
+                return null;
+            }
+//        var salt = Math.round(Math.random() * 1000000000) % 100000000;
+            var salt = 101;
+            prand += salt;
+            while (prand.length > 10) {
+                prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length), 10)).toString();
+            }
+            prand = (mult * prand + incr) % modu;
+            var enc_chr = "";
+            var enc_str = "";
+            for (var i = 0; i < str.length; i++) {
+                enc_chr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255));
+                if (enc_chr < 16) {
+                    enc_str += "0" + enc_chr.toString(16);
+                } else {
+                    enc_str += enc_chr.toString(16);
+                }
+                prand = (mult * prand + incr) % modu;
+            }
+            salt = salt.toString(16);
+            while (salt.length < 8) {
+                salt = "0" + salt;
+            }
+            enc_str += salt;
+            return enc_str;
+        },
+
+        /**
+         * 对加密后的字符串解密 {@link #encrypt}
+         * @static
+         * @param str 加密过的字符�?
+         * @param keyt 密钥
+         * @returns {String} 解密后的字符�?
+         */
+        decrypt: function (str, keyt) {
+            if (str == "") {
+                return "";
+            }
+            if (!keyt || keyt == "") {
+                keyt = "655";
+            }
+            keyt = escape(keyt);
+            if (str == null || str.length < 8) {
+                return;
+            }
+            if (keyt == null || keyt.length <= 0) {
+                return;
+            }
+            var prand = "";
+            for (var i = 0; i < keyt.length; i++) {
+                prand += keyt.charCodeAt(i).toString();
+            }
+            var sPos = Math.floor(prand.length / 5);
+            var tempmult = prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4);
+            if (sPos * 5 < prand.length) {
+                tempmult += prand.charAt(sPos * 5);
+            }
+            var mult = parseInt(tempmult);
+            var incr = Math.round(keyt.length / 2);
+            var modu = Math.pow(2, 31) - 1;
+            var salt = parseInt(str.substring(str.length - 8, str.length), 16);
+            str = str.substring(0, str.length - 8);
+            prand += salt;
+            while (prand.length > 10) {
+                prand = (parseInt(prand.substring(0, 10), 10) + parseInt(prand.substring(10, prand.length), 10)).toString();
+            }
+            prand = (mult * prand + incr) % modu;
+            var enc_chr = "";
+            var enc_str = "";
+            for (var i = 0; i < str.length; i += 2) {
+                enc_chr = parseInt(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255));
+                enc_str += String.fromCharCode(enc_chr);
+                prand = (mult * prand + incr) % modu;
+            }
+            return unescape(enc_str);
+        }
+    });
+
+    //浏览器相关方法
+    _.extend(BI, {
+        isIE: function () {
+            return $.browser.msie;
+        },
+
+        isChrome: function () {
+            return $.browser.chrome;
+        },
+
+        isFireFox: function () {
+            return $.browser.mozilla;
+        },
+
+        isOpera: function () {
+            return $.browser.opera;
+        },
+
+        isSafari: function () {
+            return $.browser.safari;
+        },
+
+        isKhtml: function () {
+            return /Konqueror|Safari|KHTML/i.test(navigator.userAgent);
+        },
+
+        isSupportCss3: function (style) {
+            var prefix = ['webkit', 'Moz', 'ms', 'o'],
+                i, len,
+                humpString = [],
+                htmlStyle = document.documentElement.style,
+                _toHumb = function (string) {
+                    return string.replace(/-(\w)/g, function ($0, $1) {
+                        return $1.toUpperCase();
+                    });
+                };
+
+            for (i in prefix) {
+                humpString.push(_toHumb(prefix[i] + '-' + style));
+            }
+            humpString.push(_toHumb(style));
+
+            for (i = 0, len = humpString.length; i < len; i++) {
+                if (humpString[i] in htmlStyle) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    });
+    //BI请求
+    _.extend(BI, {
+
+        /**
+         * 异步ajax请求
+         * @param {String} op op参数
+         * @param {String} cmd cmd参数
+         * @param {JSON} data ajax请求的参数
+         * @param {Function} callback 回调函数
+         * @param {Function} complete 回调
+         */
+        requestAsync: function (op, cmd, data, callback, complete) {
+            // if (BI.isNull(BI.REQUEST_LOADING)) {
+            //     BI.REQUEST_LOADING = BI.createWidget({
+            //         type: "bi.request_loading"
+            //     });
+            // }
+            data = data || {};
+            if (!BI.isKey(op)) {
+                op = 'fr_bi_dezi';
+            }
+            if (op === "fr_bi_dezi") {
+                data.sessionID = Data.SharingPool.get("sessionID");
+            }
+            var url = FR.servletURL + '?op=' + op + '&cmd=' + cmd + "&_=" + Math.random();
+            (BI.ajax || FR.ajax)({
+                url: url,
+                type: 'POST',
+                data: data,
+                error: function () {
+                    // BI.Msg.toast(BI.i18nText("BI-Ajax_Error"));
+                    //失败 取消、重新加载
+                    // BI.REQUEST_LOADING.setCallback(function () {
+                    //     BI.requestAsync(op, cmd, data, callback, complete);
+                    // });
+                    // BI.REQUEST_LOADING.showError();
+                },
+                complete: function (res, status) {
+                    if (BI.isFunction(callback) && status === 'success') {
+                        callback(BI.jsonDecode(res.responseText));
+                        BI.Maskers.hide(BI.RequstLoading.MASK_ID);
+                    }
+                    if (BI.isFunction(complete)) {
+                        complete();
+                    }
+                }
+            });
+        },
+
+        /**
+         * 同步ajax请求
+         * @param {String} op op参数
+         * @param {String} cmd cmd参数
+         * @param {JSON} data ajax请求的参�?
+         * @returns {Object} ajax同步请求返回的JSON对象
+         */
+        requestSync: function (op, cmd, data) {
+            data = data || {};
+            if (!BI.isKey(op)) {
+                op = 'fr_bi_dezi';
+            }
+            if (op === "fr_bi_dezi") {
+                data.sessionID = Data.SharingPool.get("sessionID");
+            }
+            var url = FR.servletURL + '?op=' + op + '&cmd=' + cmd + "&_=" + Math.random();
+            var result = {};
+            (BI.ajax || FR.ajax)({
+                url: url,
+                type: 'POST',
+                async: false,
+                data: data,
+                error: function () {
+                    BI.Msg.toast(BI.i18nText("BI-Ajax_Error"));
+                },
+                complete: function (res, status) {
+                    if (status === 'success') {
+                        result = BI.jsonDecode(res.responseText);
+                    }
+                }
+            });
+            return result;
+        },
+
+        /**
+         * 请求方法
+         * @param cmd 命令
+         * @param data 数据
+         * @param extend 参数
+         * @returns {*}
+         */
+        request: function (cmd, data, extend) {
+            extend = extend || {};
+            data = data || {};
+            var op = extend.op;
+            if (!BI.isKey(op)) {
+                op = 'fr_bi_dezi';
+            }
+            if (op === "fr_bi_dezi") {
+                data.sessionID = Data.SharingPool.get("sessionID");
+            }
+            if (extend.async === true) {
+                BI.requestAsync(op, cmd, data, extend.complete || extend.success);
+            } else {
+                return BI.requestSync(op, cmd, data);
+            }
+        }
+    });
+})(jQuery);/**
+ * 客户端观察者,主要处理事件的添加、删除、执行等
+ * @class BI.OB
+ * @abstract
+ */
+BI.OB = function (config) {
+    var props = this.props;
+    if (BI.isFunction(this.props)) {
+        props = this.props(config);
+    }
+    this.options = $.extend(this._defaultConfig(config), props, config);
+    this._init();
+    this._initRef();
+};
+$.extend(BI.OB.prototype, {
+    props: {},
+    init: function () {
+    },
+
+    _defaultConfig: function (config) {
+        return {};
+    },
+
+    _init: function () {
+        this._initListeners();
+        this.init();
+    },
+
+    _initListeners: function () {
+        var self = this;
+        if (this.options.listeners != null) {
+            $.each(this.options.listeners, function (i, lis) {
+                (lis.target ? lis.target : self)[lis.once ? 'once' : 'on']
+                (lis.eventName, _.bind(lis.action, self))
+            });
+            delete this.options.listeners;
+        }
+    },
+
+    //获得一个当前对象的引用
+    _initRef: function () {
+        if (this.options.ref) {
+            this.options.ref.call(this, this);
+        }
+    },
+
+    _getEvents: function () {
+        if (!$.isArray(this.events)) {
+            this.events = []
+        }
+        return this.events;
+    },
+
+    /**
+     * 给观察者绑定一个事件
+     * @param {String} eventName 事件的名字
+     * @param {Function} fn 事件对应的执行函数
+     */
+    on: function (eventName, fn) {
+        eventName = eventName.toLowerCase();
+        var fns = this._getEvents()[eventName];
+        if (!$.isArray(fns)) {
+            fns = [];
+            this._getEvents()[eventName] = fns;
+        }
+        fns.push(fn);
+    },
+
+    /**
+     * 给观察者绑定一个只执行一次的事件
+     * @param {String} eventName 事件的名字
+     * @param {Function} fn 事件对应的执行函数
+     */
+    once: function (eventName, fn) {
+        var proxy = function () {
+            fn.apply(this, arguments);
+            this.un(eventName, proxy);
+        };
+        this.on(eventName, proxy);
+    },
+    /**
+     * 解除观察者绑定的指定事件
+     * @param {String} eventName 要解除绑定事件的名字
+     * @param {Function} fn 事件对应的执行函数,该参数是可选的,没有该参数时,将解除绑定所有同名字的事件
+     */
+    un: function (eventName, fn) {
+        eventName = eventName.toLowerCase();
+
+        /*alex:如果fn是null,就是把eventName上面所有方法都un掉*/
+        if (fn == null) {
+            delete this._getEvents()[eventName];
+        } else {
+            var fns = this._getEvents()[eventName];
+            if ($.isArray(fns)) {
+                var newFns = [];
+                $.each(fns, function (idx, ifn) {
+                    if (ifn != fn) {
+                        newFns.push(ifn);
+                    }
+                })
+                this._getEvents()[eventName] = newFns;
+            }
+        }
+    },
+    /**
+     * 清除观察者的所有事件绑定
+     */
+    purgeListeners: function () {
+        /*alex:清空events*/
+        this.events = [];
+    },
+    /**
+     * 触发绑定过的事件
+     *
+     * @param {String} eventName 要触发的事件的名字
+     * @returns {Boolean} 如果事件函数返回false,则返回false并中断其他同名事件的执行,否则执行所有的同名事件并返回true
+     */
+    fireEvent: function () {
+        var eventName = arguments[0].toLowerCase();
+        var fns = this._getEvents()[eventName];
+        if (BI.isArray(fns)) {
+            if (BI.isArguments(arguments[1])) {
+                for (var i = 0; i < fns.length; i++) {
+                    if (fns[i].apply(this, arguments[1]) === false) {
+                        return false;
+                    }
+                }
+            } else {
+                var args = Array.prototype.slice.call(arguments, 1);
+                for (var i = 0; i < fns.length; i++) {
+                    if (fns[i].apply(this, args) === false) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+});/**
+ * Widget超类
+ * @class BI.Widget
+ * @extends BI.OB
+ *
+ * @cfg {JSON} options 配置属性
+ */
+BI.Widget = BI.inherit(BI.OB, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Widget.superclass._defaultConfig.apply(this), {
+            tagName: "div",
+            attributes: null,
+            data: null,
+
+            tag: null,
+            disabled: false,
+            invisible: false,
+            invalid: false,
+            baseCls: "",
+            extraCls: "",
+            cls: ""
+        })
+    },
+
+    //生命周期函数
+    beforeCreate: function () {
+
+    },
+
+    created: function () {
+
+    },
+
+    render: function () {
+
+    },
+
+    beforeMounted: function () {
+
+    },
+
+    mounted: function () {
+
+    },
+
+    destroyed: function () {
+    },
+
+    _init: function () {
+        BI.Widget.superclass._init.apply(this, arguments);
+        this.beforeCreate();
+        this._initRoot();
+        this._initElementWidth();
+        this._initElementHeight();
+        this._initVisualEffects();
+        this._initState();
+        this._initElement();
+        this.created();
+    },
+
+    /**
+     * 初始化根节点
+     * @private
+     */
+    _initRoot: function () {
+        var o = this.options;
+        this.widgetName = o.widgetName || BI.uniqueId("widget");
+        if (BI.isWidget(o.element)) {
+            this._parent = o.element;
+            this._parent.addWidget(this.widgetName, this);
+            this.element = this.options.element.element;
+        } else if (o.element) {
+            this.element = $(o.element);
+            this._isRoot = true;
+        } else {
+            this.element = $(document.createElement(o.tagName));
+        }
+        if (o.baseCls || o.extraCls || o.cls) {
+            this.element.addClass((o.baseCls || "") + " " + (o.extraCls || "") + " " + (o.cls || ""));
+        }
+        if (o.attributes) {
+            this.element.attr(o.attributes);
+        }
+        if (o.data) {
+            this.element.data(o.data);
+        }
+        this._children = {};
+    },
+
+    _initElementWidth: function () {
+        var o = this.options;
+        if (BI.isWidthOrHeight(o.width)) {
+            this.element.css("width", o.width);
+        }
+    },
+
+    _initElementHeight: function () {
+        var o = this.options;
+        if (BI.isWidthOrHeight(o.height)) {
+            this.element.css("height", o.height);
+        }
+    },
+
+    _initVisualEffects: function () {
+        var o = this.options;
+        if (o.invisible) {
+            this.element.hide();
+        }
+        if (o.disabled) {
+            this.element.addClass("base-disabled disabled");
+        }
+        if (o.invalid) {
+            this.element.addClass("base-invalid invalid");
+        }
+    },
+
+    _initState: function () {
+        this._isMounted = false;
+    },
+
+    _initElement: function () {
+        var self = this;
+        var els = this.render();
+        if (BI.isPlainObject(els)) {
+            els = [els];
+        }
+        if (BI.isArray(els)) {
+            BI.each(els, function (i, el) {
+                BI.createWidget(el, {
+                    element: self
+                })
+            })
+        }
+        if (this._isRoot === true) {
+            this._mount();
+        }
+    },
+
+    _setParent: function (parent) {
+        this._parent = parent;
+    },
+
+    _mount: function () {
+        var self = this;
+        var isMounted = this._isMounted;
+        if (isMounted) {
+            return;
+        }
+        if (this._isRoot === true) {
+            isMounted = true;
+        } else if (this._parent && this._parent._isMounted === true) {
+            isMounted = true;
+        }
+        if (!isMounted) {
+            return;
+        }
+        this.beforeMounted();
+        this._isMounted = true;
+        this._mountChildren();
+        BI.each(this._children, function (i, widget) {
+            widget._mount();
+        });
+        this.mounted();
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.element.append(frag);
+        }
+    },
+
+    _unMount: function () {
+        BI.each(this._children, function (i, widget) {
+            widget._unMount();
+        });
+        this._children = {};
+        this._parent = null;
+        this._isMounted = false;
+        this.destroyed();
+    },
+
+    setWidth: function (w) {
+        this.options.width = w;
+        this._initElementWidth();
+    },
+
+    setHeight: function (h) {
+        this.options.height = h;
+        this._initElementHeight();
+    },
+
+    setEnable: function (enable) {
+        if (enable === true) {
+            this.options.disabled = false;
+            this.element.removeClass("base-disabled disabled");
+        } else if (enable === false) {
+            this.options.disabled = true;
+            this.element.addClass("base-disabled disabled");
+        }
+    },
+
+    setVisible: function (visible) {
+        if (visible === true) {
+            this.options.invisible = false;
+            this.element.show();
+        } else if (visible === false) {
+            this.options.invisible = true;
+            this.element.hide();
+        }
+    },
+
+    setValid: function (valid) {
+        this.options.invalid = !valid;
+        if (valid === true) {
+            this.element.removeClass("base-invalid invalid");
+        } else if (valid === false) {
+            this.element.addClass("base-invalid invalid");
+        }
+    },
+
+    getWidth: function () {
+        return this.options.width;
+    },
+
+    getHeight: function () {
+        return this.options.height;
+    },
+
+    isValid: function () {
+        return !this.options.invalid;
+    },
+
+    addWidget: function (name, widget) {
+        var self = this;
+        if (name instanceof BI.Widget) {
+            widget = name;
+            name = widget.getName();
+        }
+        name = name || widget.getName() || BI.uniqueId("widget");
+        if (this._children[name]) {
+            throw new Error("name has already been existed");
+        }
+        widget._setParent(this);
+        widget.on(BI.Events.DESTROY, function () {
+            delete self._children[name]
+        });
+        return (this._children[name] = widget);
+    },
+
+    getWidgetByName: function (name) {
+        if (!BI.isKey(name) || name == this.getName()) {
+            return this;
+        }
+        name = name + "";
+        var widget = void 0, other = {};
+        BI.any(this._children, function (i, wi) {
+            if (i === name) {
+                widget = wi;
+                return true;
+            }
+            other[i] = wi;
+        });
+        if (!widget) {
+            BI.any(other, function (i, wi) {
+                return (widget = wi.getWidgetByName(i));
+            });
+        }
+        return widget;
+    },
+
+    removeWidget: function (name) {
+        delete this._children[name];
+    },
+
+    hasWidget: function (name) {
+        return this._children[name] != null;
+    },
+
+    getName: function () {
+        return this.widgetName;
+    },
+
+    setTag: function (tag) {
+        this.options.tag = tag;
+    },
+
+    getTag: function () {
+        return this.options.tag;
+    },
+
+    attr: function (key, value) {
+        if (BI.isNotNull(value)) {
+            return this.options[key] = value;
+        }
+        return this.options[key];
+    },
+
+    getText: function () {
+
+    },
+
+    setText: function (text) {
+
+    },
+
+    getValue: function () {
+
+    },
+
+    setValue: function (value) {
+
+    },
+
+    isEnabled: function () {
+        return !this.options.disabled;
+    },
+
+    isVisible: function () {
+        return !this.options.invisible;
+    },
+
+    disable: function () {
+        this.setEnable(false);
+    },
+
+    enable: function () {
+        this.setEnable(true);
+    },
+
+    valid: function () {
+        this.setValid(true);
+    },
+
+    invalid: function () {
+        this.setValid(false);
+    },
+
+    invisible: function () {
+        this.setVisible(false);
+    },
+
+    visible: function () {
+        this.setVisible(true);
+    },
+
+    empty: function () {
+        BI.each(this._children, function (i, widget) {
+            widget._unMount();
+        });
+        this._children = {};
+        this.element.empty();
+    },
+
+    destroy: function () {
+        this._unMount();
+        this.element.destroy();
+        this.fireEvent(BI.Events.DESTROY);
+    }
+});BI.Model = BI.inherit(BI.M, {
+    _defaultConfig: function () {
+        return {
+            "default": "just a default",
+            "current": void 0
+        }
+    },
+
+    _static: function () {
+        return {};
+    },
+
+    _init: function () {
+        BI.Model.superclass._init.apply(this, arguments);
+        this.on("change:current", function (obj, val) {
+            BI.isNotNull(val) && this.refresh(val);
+        }).on("change", function (changed, prev, context, options) {
+            if (this._start === true || BI.has(changed, "current")) {
+                return;
+            }
+            this.actionStart();
+            if (!this.local()) {
+                !BI.has(this._tmp, BI.keys(changed)) && this.parent && this.parent._change(this);
+                this._changing_ = true;
+                this.change(changed, prev, context, options);
+                this._changing_ = false;
+            }
+        });
+
+        this._tmp = {};//过渡属性
+
+        this._hass = {};
+        this._gets = [];//记录交互行为
+        this._start = false;
+        this._changing_ = false;
+
+        this._read = BI.debounce(BI.bind(this.fetch, this), 30);
+        this._save = BI.debounce(BI.bind(this.save, this), 30);
+        this._F = [];
+    },
+
+    toJSON: function () {
+        var json = BI.Model.superclass.toJSON.apply(this, arguments);
+        delete json["baseCls"];
+        delete json["current"];
+        delete json["default"];
+        delete json["parent"];
+        delete json["rootURL"];
+        delete json["id"];
+        delete json["tag"];
+        BI.each(this._gets, function (i, action) {
+            delete json[action];
+        });
+        return json;
+    },
+
+    copy: function () {
+        if (this._start === true || this._changing_ === true) {
+            this._F.push({f: this.copy, arg: arguments});
+            return;
+        }
+        this.trigger("copy");
+    },
+    //子节点的一个类似副本
+    similar: function (value, key1, key2, key3) {
+        return value;
+    },
+
+    _map: function (child) {
+        var self = this;
+        var map = {}, current = {};
+        var mapping = function (key, ch) {
+            key = key + "";
+            if (key === "") {
+                return;
+            }
+            var keys = key.split('.');
+            if (!map[keys[0]]) {
+                map[keys[0]] = self.get(keys[0]);
+            }
+            var parent = map, last = void 0;
+            BI.each(keys, function (i, k) {
+                last && (parent = parent[last] || (parent[last] = {}));
+                last = k;
+            });
+            parent[last] = ch.toJSON();
+        };
+        BI.each(this._childs, function (key, chs) {
+            if (!BI.isArray(chs)) {
+                chs = [chs];
+            }
+            BI.each(chs, function (i, ch) {
+                if (ch === child) {
+                    current[key] = child;
+                    return;
+                }
+                //mapping(key, ch);
+            })
+        });
+        BI.each(current, function (key, ch) {
+            mapping(key, ch);
+        });
+        var tmp = {};
+        BI.each(this._tmp, function (k) {
+            if (map[k]) {
+                tmp[k] = map[k];
+                delete map[k];
+            }
+        });
+        this.tmp(tmp);
+        return map;
+    },
+
+    _change: function (child) {
+        this.set(this._map(child));
+        return this;
+    },
+
+    splice: function (old, key1, key2, key3) {
+
+    },
+
+    duplicate: function (copy, key1, key2, key3) {
+
+    },
+
+    change: function (changed, prev) {
+
+    },
+
+    actionStart: function () {
+        this._start = true;
+        return this;
+    },
+
+    actionEnd: function () {
+        var self = this;
+        this._start = false;
+        var _gets = this._gets.slice(0), _F = this._F.slice(0);
+        this._gets = [];
+        this._hass = {};
+        this._F = [];
+        BI.each(_gets, function (i, action) {
+            self.unset(action, {silent: true});
+        });
+        BI.each(_F, function (i, fn) {
+            fn.f.apply(self, fn.arg);
+        });
+        return this;
+    },
+
+    addChild: function (name, child) {
+        name = name + "";
+        var self = this;
+        this._childs || (this._childs = {});
+        if (this._childs[name]) {
+            if (BI.isArray(this._childs[name])) {
+                this._childs[name].push(child);
+            } else {
+                this._childs[name] = [this._childs[name]].concat(child)
+            }
+        } else {
+            this._childs[name] = child;
+        }
+        child && child.on("destroy", function () {
+            var keys = name.split('.');
+            var g = self.get(keys[0]), p, c;
+            var sset = !!self._tmp[keys[0]] ? "tmp" : "set", unset = "un" + sset;
+
+            BI.each(keys, function (i, k) {
+                if (i === 0) {
+                    c = g;
+                    return;
+                }
+                p = c;
+                c = c[k];
+            });
+            self.removeChild(name, child);
+            var newKeys = BI.clone(keys);
+            keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g));
+            keys.length > 1 ? (delete p[keys[keys.length - 1]], self[sset](keys[0], g, {silent: true})) : self[unset](name, {silent: true});
+            !BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self);
+            self.splice.apply(self, newKeys);
+            self.trigger("splice", newKeys);
+        }).on("copy", function () {
+            var keys = name.split('.');
+            var g = self.get(keys[0]), p, c;
+            var sset = !!self._tmp[keys[0]] ? "tmp" : "set";
+            BI.each(keys, function (i, k) {
+                if (i === 0) {
+                    c = g;
+                    return;
+                }
+                p = c;
+                c = c[k];
+            });
+            var copy = BI.UUID(), newKeys = BI.clone(keys);
+            keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g));
+            var backup = self.similar.apply(self, newKeys);
+            keys.length > 1 ? (p[copy] = backup, self[sset](keys[0], g, {silent: true})) : self[sset](copy, backup, {silent: true});
+            keys.unshift(copy);
+            !BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self);
+            self.duplicate.apply(self, keys);
+            self.trigger("duplicate", keys);
+        });
+    },
+
+    removeChild: function (name, child) {
+        if (BI.isArray(this._childs[name])) {
+            BI.remove(this._childs[name], child);
+            if (BI.isEmpty(this._childs[name])) {
+                delete this._childs[name];
+            }
+            return;
+        }
+        delete this._childs[name];
+    },
+
+    has: function (attr, istemp) {
+        if (istemp === true) {
+            return _.has(this.tmp, attr);
+        }
+        if (this._start === true && this._changing_ === false) {
+            this._hass[attr] = true;
+        }
+        return BI.Model.superclass.has.apply(this, arguments);
+    },
+
+    cat: function (attr) {
+        if (_.has(this._tmp, attr)) {
+            return this._tmp[attr];
+        }
+        if (this._start === true && this._hass[attr]) {
+            delete this._hass[attr];
+            switch (attr) {
+                case "default":
+                    break;
+                case "current":
+                    break;
+                default :
+                    this._gets.push(attr);
+                    break;
+            }
+        }
+        if (_.has(this.attributes, attr)) {
+            return this.attributes[attr];
+        }
+        var sta = _.result(this, "_static");
+        return BI.isFunction(sta[attr]) ? sta[attr].apply(this, BI.values(arguments).slice(1)) : sta[attr];
+    },
+
+    get: function () {
+        return BI.deepClone(this.cat.apply(this, arguments));
+    },
+
+    set: function (key, val, options) {
+        if (this._start === true || this._changing_ === true) {
+            this._F.push({f: this.set, arg: arguments});
+            return this;
+        }
+        return BI.Model.superclass.set.apply(this, arguments);
+    },
+
+    unset: function (attr, options) {
+        var self = this;
+        BI.each(this._childs, function (key, model) {
+            key = key + "";
+            var keys = key.split('.');
+            if (_.isEqual(attr, keys[0])) {
+                delete self._childs[attr];
+                if (!BI.isArray(model)) {
+                    model = [model];
+                }
+                BI.each(model, function (i, m) {
+                    m.trigger("unset");
+                });
+            }
+        });
+        return BI.Model.superclass.unset.apply(this, arguments);
+    },
+
+    tmp: function (key, val, options) {
+        if (this._start === true || this._changing_ === true) {
+            this._F.push({f: this.tmp, arg: arguments});
+            return this;
+        }
+        var attr, attrs, unset, changes, silent, changing, changed, prev, current;
+        if (key == null) return this;
+        if (typeof key === 'object') {
+            attrs = key;
+            options = val;
+        } else {
+            (attrs = {})[key] = val;
+        }
+        options || (options = {});
+
+        unset = options.unset;
+        silent = options.silent;
+        changes = [];
+        changing = this._changingTmp;
+        this._changingTmp = true;
+
+        if (!changing) {
+            this._previousTmp = _.clone(this._tmp);
+            this.changedTmp = {};
+        }
+        if (!this._previousTmp) {
+            this._previousTmp = _.clone(this._tmp);
+        }
+        current = this._tmp, prev = this._previousTmp;
+
+        for (attr in attrs) {
+            val = attrs[attr];
+            if (!_.isEqual(current[attr], val)) changes.push(attr);
+            if (!_.isEqual(prev[attr], val)) {
+                this.changedTmp[attr] = val;
+            } else {
+                delete this.changedTmp[attr];
+            }
+            unset ? delete current[attr] : current[attr] = val;
+        }
+
+        if (!silent) {
+            if (changes.length) this._pendingTmp = options;
+            for (var i = 0, length = changes.length; i < length; i++) {
+                this.trigger('change:' + changes[i], this, current[changes[i]], options);
+            }
+        }
+
+        if (changing) return this;
+        changed = BI.clone(this.changedTmp);
+        if (!silent) {
+            while (this._pendingTmp) {
+                options = this._pendingTmp;
+                this._pendingTmp = false;
+                this.trigger('change', changed, prev, this, options);
+            }
+        }
+        this._pendingTmp = false;
+        this._changingTmp = false;
+        if (!silent && changes.length) this.trigger("changed", changed, prev, this, options);
+        return this;
+    },
+
+    untmp: function (attr, options) {
+        var self = this;
+        BI.each(this._childs, function (key, model) {
+            key = key + "";
+            var keys = key.split('.');
+            if (_.isEqual(attr, keys[0])) {
+                delete self._childs[attr];
+                if (!BI.isArray(model)) {
+                    model = [model];
+                }
+                BI.each(model, function (i, m) {
+                    m.trigger("unset");
+                });
+            }
+        });
+        return this.tmp(attr, void 0, _.extend({}, options, {unset: true}));
+    },
+
+    cancel: function (options) {
+        var self = this;
+        var tmp = BI.clone(this._tmp);
+        this._tmp = {};
+        BI.each(tmp, function (k) {
+            self.untmp(k, options);
+        });
+    },
+
+    submit: function () {
+        var tmp = BI.clone(this._tmp);
+        this._tmp = {};
+        this.set(tmp);
+        return this;
+    },
+
+    urlRoot: function () {
+        return FR.servletURL;
+    },
+
+    parse: function (data) {
+        return data;
+    },
+
+    setEditing: function (edit) {
+        this._editing = edit;
+    },
+
+    getEditing: function () {
+        if (this._start !== true) {
+            throw new Error("getEditing函数只允许在local中调用");
+        }
+        return this._editing;
+    },
+
+    local: function () {
+
+    },
+
+    load: function (data) {
+
+    },
+
+    refresh: function () {
+
+    },
+
+    /**
+     * 更新整个model
+     */
+    updateURL: function () {
+
+    },
+    /**
+     * 添加一个元素或删除一个元素或修改一个元素
+     */
+    patchURL: function () {
+
+    },
+    /**
+     * 删除整个model, destroy方法调用
+     */
+    deleteURL: function () {
+
+    },
+    /**
+     * 读取model
+     */
+    readURL: function () {
+
+    },
+
+    read: function (options) {
+        if (this._start == true || this._changing_ === true) {
+            this._F.push({f: this.read, arg: arguments});
+            return;
+        }
+        this._read(options);
+    },
+
+    update: function (options) {
+        if (this._start == true || this._changing_ === true) {
+            this._F.push({f: this.update, arg: arguments});
+            return;
+        }
+        this._save(null, options);
+    },
+
+    patch: function (options) {
+        if (this._start == true || this._changing_ === true) {
+            this._F.push({f: this.patch, arg: arguments});
+            return;
+        }
+        this._save(null, BI.extend({}, options, {
+            patch: true
+        }));
+    }
+});/**
+ * @class BI.View
+ * @extends BI.V
+ * @type {*|void|Object}
+ */
+BI.View = BI.inherit(BI.V, {
+
+    _init: function () {
+        BI.View.superclass._init.apply(this, arguments);
+        var self = this;
+        this.listenTo(this.model, "change:current", function (obj, val) {
+            if (BI.isNotNull(val) && val.length > 0) {
+                this.refresh(val);
+            }
+        }).listenTo(this.model, "change", function (changed) {
+            this.delegateEvents();
+        }).listenTo(this.model, "changed", function (changed, prev, context, options) {
+            if (BI.has(changed, "current") && BI.size(changed) > 1) {
+                throw new Error("refresh操作不能调用set操作");
+            }
+            var notLocal = !BI.has(changed, "current") && !this.local() && this.notifyParent().notify();
+            this.model.actionEnd() && this.actionEnd();
+            this.model._changing_ = true;
+            notLocal && !BI.isEmpty(changed) && this.change(changed, prev, context, options);
+            this.model._changing_ = false;
+            this.model.actionEnd() && this.actionEnd();
+        }).listenTo(this.model, "destroy", function () {
+            this.destroy();
+        }).listenTo(this.model, "unset", function () {
+            this.destroy();
+        }).listenTo(this.model, "splice", function (arg) {
+            this.splice.apply(this, arg);
+        }).listenTo(this.model, "duplicate", function (arg) {
+            this.duplicate.apply(this, arg);
+        });
+        this._F = [];
+        var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"];
+        flatten = BI.makeObject(flatten, true);
+        BI.each(this.constructor.caller.caller.prototype, function (key) {
+            if (flatten[key]) {
+                return;
+            }
+            var f = self[key];
+            if (BI.isFunction(f)) {
+                self[key] = BI.bind(function () {
+                    if (this.model._start === true) {
+                        this._F.push({f: f, arg: arguments});
+                        return;
+                    }
+                    return f.apply(this, arguments);
+                }, self);
+            }
+        })
+    },
+
+    change: function (changed, prev) {
+
+    },
+
+    actionEnd: function () {
+        var self = this;
+        var _F = this._F.slice(0);
+        this._F = [];
+        BI.each(_F, function (i, f) {
+            f.f.apply(self, f.arg);
+        });
+        return this;
+    },
+
+    delegateEvents: function (events) {
+        if (!(events || (events = BI.deepClone(_.result(this, 'events'))))) return this;
+        var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+        for (var key in events) {
+            var method = events[key];
+            if (!_.isFunction(method)) method = this[events[key]];
+            if (!method) continue;
+            var match = key.match(delegateEventSplitter);
+            var ev = true;
+            switch (match[1]) {
+                case "draggable":
+                    break;
+                case "droppable":
+                    break;
+                case "sortable":
+                    break;
+                case "resizable":
+                    break;
+                case "hover":
+                    break;
+                default :
+                    ev = false;
+                    break;
+            }
+
+            var off = new BI.OffList({
+                event: match[1] + '.delegateEvents' + this.cid
+            });
+
+            var keys = match[2].split('.');
+            var handle = keys[1];
+            var bind = ev ? new BI.EventList({
+                event: match[1],
+                handle: handle,
+                callback: BI.bind(method, this)
+            }) : new BI.ListenerList({
+                event: match[1] + '.delegateEvents' + this.cid,
+                handle: handle,
+                callback: BI.bind(method, this),
+                context: this
+            });
+
+            var list = [];
+            if (this[keys[0]] && (this[keys[0]] instanceof $ || this[keys[0]].element instanceof $)) {
+                list = [this[keys[0]]]
+                delete events[key];
+            } else if (BI.isArray(this[keys[0]]) || BI.isPlainObject(this[keys[0]])) {
+                list = this[keys[0]]
+                delete events[key];
+            }
+            off.populate(list);
+            bind.populate(list);
+        }
+        return BI.View.superclass.delegateEvents.apply(this, [events]);
+    },
+
+    _vessel: function () {
+        this._cardLayouts = {};
+        this._cardLayouts[this.getName()] = new BI.CardLayout({
+            element: this
+        });
+        var vessel = BI.createWidget();
+        this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel);
+        return vessel.element;
+    },
+
+    _render: function (vessel) {
+        return this;
+    },
+
+    /**
+     * 创建儿子所在容器
+     * @param key
+     * @param vessel
+     * @param options  isLayer:是否是弹出层, defaultShowName:默认显示项
+     * @returns {BI.View}
+     */
+    addSubVessel: function (key, vessel, options) {
+        options || (options = {});
+        this._cardLayouts || (this._cardLayouts = {});
+        var id = key + this.cid;
+        options.isLayer && (vessel = BI.Layers.has(id) ? BI.Layers.get(id) : BI.Layers.create(id, vessel));
+        if (this._cardLayouts[key]) {
+            options.defaultShowName && this._cardLayouts[key].setDefaultShowName(options.defaultShowName);
+            this._cardLayouts[key].setElement(vessel) && this._cardLayouts[key].resize();
+            return this;
+        }
+        this._cardLayouts[key] = BI.createWidget({
+            type: "bi.card",
+            element: vessel,
+            defaultShowName: options.defaultShowName
+        });
+        return this;
+    },
+
+    removeSubVessel: function (key) {
+        var self = this, id = key + this.cid;
+        BI.Layers.remove(id);
+        var cardNames = this._cardLayouts[key] && this._cardLayouts[key].getAllCardNames();
+        BI.each(cardNames, function (i, name) {
+            delete self._cards[name];
+        });
+        this._cardLayouts[key] && this._cardLayouts[key].destroy();
+        return this;
+    },
+
+    createView: function (url, modelData, viewData) {
+        return BI.Factory.createView(url, this.get(url), modelData, viewData);
+    },
+
+    /**
+     * 跳转到指定的card
+     * @param cardName
+     */
+    skipTo: function (cardName, layout, modelData, viewData, options) {
+        if (this.model._start === true || this._changing_ === true) {
+            this._F.push({f: this.skipTo, arg: arguments});
+            return this;
+        }
+        var self = this, isValid = BI.isKey(modelData), data = void 0;
+        BI.isKey(layout) && (layout = layout + "");
+        layout = layout || this.getName();
+        options || (options = {});
+        if (isValid) {
+            modelData = modelData + "";//避免modelData是数字
+            var keys = modelData.split('.');
+            BI.each(keys, function (i, k) {
+                if (i === 0) {
+                    data = self.model.get(k) || {};
+                } else {
+                    data = data[k] || {};
+                }
+            });
+            data.id = options.id || keys[keys.length - 1];
+        } else {
+            data = modelData;
+        }
+        BI.extend(data, options.data);
+        var action = options.action || new BI.ShowAction();
+        var cardLayout = this._cardLayouts[layout];
+        if (!cardLayout) {
+            return this;
+        }
+        cardLayout.setVisible(true);
+        if (BI.isKey(cardName) && !cardLayout.isCardExisted(cardName)) {
+            var view = this.createView(this.rootURL + "/" + cardName, data, viewData);
+            isValid && this.model.addChild(modelData, view.model);
+            view.listenTo(view.model, "destroy", function () {
+                delete self._cards[cardName];
+                cardLayout.deleteCardByName(cardName);
+                if (cardLayout.isAllCardHide()) {
+                    cardLayout.setVisible(false);
+                    BI.Layers.hide(layout + self.cid);
+                }
+            }).listenTo(view.model, "unset", function () {
+                delete self._cards[cardName];
+                cardLayout.deleteCardByName(cardName);
+            });
+            cardLayout.addCardByName(cardName, view);
+            this._cards || (this._cards = {});
+            this._cards[cardName] = view;
+            data = {};
+            this.on("end:" + view.cid, function () {
+                var isNew = false, t, keys;
+                if (isValid) {
+                    keys = modelData.split('.');
+                    BI.each(keys, function (i, k) {
+                        if (i === 0) {
+                            t = self.model.get(k) || (isNew = true);
+                        } else {
+                            t = t[k] || (isNew = true);
+                        }
+                    });
+                }
+                if (isNew) {
+                    delete self._cards[cardName];
+                    self.model.removeChild(modelData, view.model);
+                    cardLayout.deleteCardByName(cardName);
+                    view.destroy();
+                    cardLayout.setVisible(false);
+                }
+                action.actionBack(view, null, function () {
+                    if (cardLayout.isAllCardHide()) {
+                        cardLayout.setVisible(false);
+                        BI.Layers.hide(layout + self.cid);
+                    }
+                    !isNew && (self.listenEnd.apply(self, isValid ? keys : [modelData]) !== false) && self.populate();
+                })
+            }).on("change:" + view.cid, _.bind(this.notifyParent, this));
+        }
+        BI.isKey(cardName) && BI.Layers.show(layout + this.cid);
+        cardLayout.showCardByName(cardName, action, function () {
+            BI.isKey(cardName) && self._cards[cardName].populate(data, options);
+        });
+        !BI.isKey(cardName) && BI.Layers.hide(layout + this.cid);
+        return this._cards[cardName];
+    },
+
+    listenEnd: function (key1, key2, key3) {
+        return this;
+    },
+
+    /**
+     * 告诉父亲我的操作结束了,后面的事情任由父亲处置
+     * @param force 强制下次再次进入该节点时不进行刷新操作, 默认执行刷新
+     * @returns {BI.View}
+     */
+    notifyParentEnd: function (force) {
+        this.parent && this.parent.trigger("end:" + this.cid);
+        this.trigger("end");
+        !force && this.notify();
+        return this;
+    },
+
+    /**
+     * 通知父亲我的数据发生了变化
+     */
+    notifyParent: function () {
+        this.parent && this.parent.notify().trigger("change:" + this.cid);
+        return this;
+    },
+
+    /**
+     * 告诉Model数据改变了
+     */
+    notify: function () {
+        this.model.unset("current", {silent: true});
+        return this;
+    },
+
+    getName: function () {
+        return "VIEW"
+    },
+
+    /**
+     * 全局刷新
+     * @param current
+     */
+    refresh: function (current) {
+    },
+    /**
+     * 局部刷新
+     */
+    local: function () {
+        return false;
+    },
+
+    load: function (data) {
+
+    },
+
+    readData: function (force, options) {
+        options || (options = {});
+        var self = this;
+        var args = [].slice.call(arguments, 2);
+        if (!force && this._readed === true) {//只从后台获取一次数据
+            callback(this.model.toJSON());
+            return;
+        }
+        //采用静默方式读数据,该数据变化不引起data的change事件触发
+        var success = options.success;
+        this.read(BI.extend({
+            silent: true
+        }, options, {
+            success: function (data, model) {
+                callback(data);
+                !force && (self._readed = true);
+                self.delegateEvents();
+                success && success(data, model);
+            }
+        }));
+        function callback(data) {
+            self.model.load(data);
+            self.load(data);
+            BI.each(args, function (i, arg) {
+                if (BI.isFunction(arg)) {
+                    arg.apply(self, [data]);
+                }
+            })
+        }
+    },
+
+    //处理model的通用方法
+    cat: function () {
+        return this.model.cat.apply(this.model, arguments);
+    },
+
+    get: function () {
+        return this.model.get.apply(this.model, arguments);
+    },
+
+    set: function () {
+        return this.model.set.apply(this.model, arguments);
+    },
+
+    has: function () {
+        return this.model.has.apply(this.model, arguments);
+    },
+
+    getEditing: function () {
+        return this.model.getEditing();
+    },
+
+    read: function (options) {
+        this.model.read(options)
+    },
+
+    update: function (options) {
+        this.model.update(options);
+    },
+
+    patch: function (options) {
+        this.model.patch(options);
+    },
+
+    reading: function (options) {
+        var self = this;
+        var name = BI.UUID();
+        this.read(BI.extend({}, options, {
+            beforeSend: function () {
+                var loading = BI.createWidget({
+                    type: 'bi.vertical',
+                    items: [{
+                        type: "bi.layout",
+                        height: 30,
+                        cls: "loading-background"
+                    }],
+                    element: BI.Maskers.make(name, self)
+                });
+                loading.setVisible(true);
+            },
+            complete: function (data) {
+                options.complete && options.complete(data);
+                BI.Maskers.remove(name);
+            }
+        }));
+    },
+
+    updating: function (options) {
+        var self = this;
+        var name = BI.UUID();
+        this.update(BI.extend({}, options, {
+            noset: true,
+            beforeSend: function () {
+                var loading = BI.createWidget({
+                    type: 'bi.vertical',
+                    items: [{
+                        type: "bi.layout",
+                        height: 30,
+                        cls: "loading-background"
+                    }],
+                    element: BI.Maskers.make(name, self)
+                });
+                loading.setVisible(true);
+            },
+            complete: function (data) {
+                options.complete && options.complete(data);
+                BI.Maskers.remove(name);
+            }
+        }));
+    },
+
+    patching: function (options) {
+        var self = this;
+        var name = BI.UUID();
+        this.patch(BI.extend({}, options, {
+            noset: true,
+            beforeSend: function () {
+                var loading = BI.createWidget({
+                    type: 'bi.vertical',
+                    items: [{
+                        type: "bi.layout",
+                        height: 30,
+                        cls: "loading-background"
+                    }],
+                    element: BI.Maskers.make(name, self)
+                });
+                loading.setVisible(true);
+            },
+            complete: function (data) {
+                options.complete && options.complete(data);
+                BI.Maskers.remove(name);
+            }
+        }));
+    },
+
+    populate: function (modelData, options) {
+        var self = this;
+        options || (options = {});
+        if (options.force === true) {
+            this.notify();
+        }
+        if (this._cardLayouts && this._cardLayouts[this.getName()]) {
+            this._cardLayouts[this.getName()].showCardByName(this.getName());
+        }
+        //BI.each(this._cardLayouts, function (key, layout) {
+        //    layout.showCardByName(layout.getDefaultShowName() || self.getName());
+        //});
+        //BI.each(this._cards, function (i, card) {
+        //    card.notify && card.notify();
+        //});
+        if (this._F.length > 0) {
+            throw new Error("流程错误");
+        }
+        if (options.force === true) {
+            this.model.set(modelData, options).set({current: this.model.get("default")});
+            return;
+        }
+        if (options.force === false) {
+            this.model.set(modelData);
+            return;
+        }
+        var filter = BI.clone(modelData || {});
+        delete filter.id;
+        var contains = BI.has(this.model.toJSON(), _.keys(filter));
+        var match = BI.isEmpty(filter) || (contains && this.model.matches(modelData));
+        if (match === true) {
+            this.model.set({current: this.model.get("default")});
+        } else if (contains === false) {
+            this.model.set(modelData);
+        } else {
+            this.model.set(modelData, options).set({current: this.model.get("default")});
+        }
+    },
+
+    //删除子节点触发
+    splice: function (old, key1, key2, key3) {
+
+    },
+
+    //复制子节点触发
+    duplicate: function (copy, key1, key2, key3) {
+
+    },
+
+    destroy: function () {
+        BI.each(this._cardLayouts, function (name, card) {
+            card && card.destroy();
+        });
+        delete this._cardLayouts;
+        delete this._cards;
+        this.remove();
+        this.destroyed();
+    },
+
+    destroyed: function () {
+
+    }
+});(function ($) {
+
+    var kv = {}; // alex:键(编辑器简称,如text)值(也是一个字符串,如FR.TextEditor)对
+    $.shortcut = BI.shortcut = function (xtype, cls) {
+        if (kv[xtype] != null) {
+            throw ("shortcut:[" + xtype + "] has been registed");
+        }
+        kv[xtype] = cls;
+        $.extend(cls.prototype, {
+            xtype: xtype
+        })
+    };
+
+    // 根据配置属性生成widget
+    var createWidget = function (config) {
+        // alex:如果是一个jquery对象,就在外面套一层,变成一个FR.Widget
+        if (config instanceof $) {
+            return new BI.Widget({
+                element: config
+            });
+        }
+        if (config['classType']) {
+            return new (new Function('return ' + config['classType'] + ';')())(config);
+        }
+
+        if (!config.type) {
+
+        }
+        var xtype = config.type.toLowerCase();
+        var cls = kv[xtype];
+        return new cls(config);
+    };
+
+    BI.createWidget = function (item, options) {
+        var el;
+        options || (options = {});
+        if (BI.isEmpty(item) && BI.isEmpty(options)) {
+            return BI.createWidget({
+                type: "bi.layout"
+            });
+        }
+        if (BI.isWidget(item)) {
+            return item;
+        }
+        if (item && (item.type || options.type)) {
+            el = BI.extend({}, options, item);
+            return BI.Plugin.getObject(el.type, createWidget(BI.Plugin.getWidget(el.type, el)));
+        }
+        if (item && item.el && (item.el.type || options.type)) {
+            el = BI.extend({}, options, item.el);
+            return BI.Plugin.getObject(el.type, createWidget(BI.Plugin.getWidget(el.type, el)));
+        }
+        if (item && BI.isWidget(item.el)) {
+            return item.el;
+        }
+        throw new Error('无法根据item创建组件');
+    }
+
+})(jQuery);(function (window, undefined) {
+    function aspect(type) {
+        return function (target, methodName, advice) {
+            var exist = target[methodName],
+                dispatcher;
+
+            if (!exist || exist.target != target) {
+                dispatcher = target[methodName] = function () {
+                    // before methods
+                    var beforeArr = dispatcher.before;
+                    var args = arguments, next;
+                    for (var l = beforeArr.length; l--;) {
+                        next = beforeArr[l].advice.apply(this, args);
+                        if (next === false) {
+                            return false;
+                        }
+                        args = next || args;
+                    }
+                    // target method
+                    var rs = dispatcher.method.apply(this, args);
+                    // after methods
+                    var afterArr = dispatcher.after;
+                    for (var i = 0, ii = afterArr.length; i < ii; i++) {
+                        next = afterArr[i].advice.call(this, rs, args);
+                        if (rs === false) {
+                            return false;
+                        }
+                        args = next || args;
+                    }
+                    return rs;
+                };
+
+                dispatcher.before = [];
+                dispatcher.after = [];
+
+                if (exist) {
+                    dispatcher.method = exist;
+                }
+                dispatcher.target = target;
+            }
+
+            var aspectArr = (dispatcher || exist)[type];
+            var obj = {
+                advice: advice,
+                _index: aspectArr.length,
+                remove: function () {
+                    aspectArr.splice(this._index, 1);
+                }
+            };
+            aspectArr.push(obj);
+
+            return obj;
+        };
+    }
+
+    BI.aspect = {
+        before: aspect("before"),
+        after: aspect("after")
+    };
+
+    return BI.aspect;
+
+})(window);;
+!(function () {
+
+    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+
+    // private method for UTF-8 encoding
+    var _utf8_encode = function (string) {
+        string = string.replace(/\r\n/g, "\n");
+        var utftext = "";
+
+        for (var n = 0; n < string.length; n++) {
+
+            var c = string.charCodeAt(n);
+
+            if (c < 128) {
+                utftext += String.fromCharCode(c);
+            } else if ((c > 127) && (c < 2048)) {
+                utftext += String.fromCharCode((c >> 6) | 192);
+                utftext += String.fromCharCode((c & 63) | 128);
+            } else {
+                utftext += String.fromCharCode((c >> 12) | 224);
+                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+                utftext += String.fromCharCode((c & 63) | 128);
+            }
+
+        }
+
+        return utftext;
+    };
+
+    // private method for UTF-8 decoding
+    var _utf8_decode = function (utftext) {
+        var string = "";
+        var i = 0;
+        var c = 0, c3 = 0, c2 = 0;
+
+        while (i < utftext.length) {
+
+            c = utftext.charCodeAt(i);
+
+            if (c < 128) {
+                string += String.fromCharCode(c);
+                i++;
+            } else if ((c > 191) && (c < 224)) {
+                c2 = utftext.charCodeAt(i + 1);
+                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+                i += 2;
+            } else {
+                c2 = utftext.charCodeAt(i + 1);
+                c3 = utftext.charCodeAt(i + 2);
+                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+                i += 3;
+            }
+
+        }
+        return string;
+    };
+
+    _.extend(BI, {
+
+        encode: function (input) {
+            var output = "";
+            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+            var i = 0;
+
+            input = _utf8_encode(input);
+
+            while (i < input.length) {
+
+                chr1 = input.charCodeAt(i++);
+                chr2 = input.charCodeAt(i++);
+                chr3 = input.charCodeAt(i++);
+
+                enc1 = chr1 >> 2;
+                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+                enc4 = chr3 & 63;
+
+                if (isNaN(chr2)) {
+                    enc3 = enc4 = 64;
+                } else if (isNaN(chr3)) {
+                    enc4 = 64;
+                }
+
+                output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
+
+            }
+
+            return output;
+        },
+
+        // public method for decoding
+        decode: function (input) {
+            var output = "";
+            var chr1, chr2, chr3;
+            var enc1, enc2, enc3, enc4;
+            var i = 0;
+
+            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+            while (i < input.length) {
+
+                enc1 = _keyStr.indexOf(input.charAt(i++));
+                enc2 = _keyStr.indexOf(input.charAt(i++));
+                enc3 = _keyStr.indexOf(input.charAt(i++));
+                enc4 = _keyStr.indexOf(input.charAt(i++));
+
+                chr1 = (enc1 << 2) | (enc2 >> 4);
+                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+                chr3 = ((enc3 & 3) << 6) | enc4;
+
+                output = output + String.fromCharCode(chr1);
+
+                if (enc3 != 64) {
+                    output = output + String.fromCharCode(chr2);
+                }
+                if (enc4 != 64) {
+                    output = output + String.fromCharCode(chr3);
+                }
+
+            }
+
+            output = _utf8_decode(output);
+
+            return output;
+
+        }
+    })
+})();BI.CellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize) {
+    this._cellSizeGetter = cellSizeGetter;
+    this._cellCount = cellCount;
+    this._estimatedCellSize = estimatedCellSize;
+    this._cellSizeAndPositionData = {};
+    this._lastMeasuredIndex = -1;
+};
+
+BI.CellSizeAndPositionManager.prototype = {
+    constructor: BI.CellSizeAndPositionManager,
+    configure: function (cellCount, estimatedCellSize) {
+        this._cellCount = cellCount;
+        this._estimatedCellSize = estimatedCellSize;
+    },
+
+    getCellCount: function () {
+        return this._cellCount;
+    },
+
+    getEstimatedCellSize: function () {
+        return this._estimatedCellSize;
+    },
+
+    getLastMeasuredIndex: function () {
+        return this._lastMeasuredIndex;
+    },
+
+    getSizeAndPositionOfCell: function (index) {
+        if (index < 0 || index >= this._cellCount) {
+            return;
+        }
+        if (index > this._lastMeasuredIndex) {
+            var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
+            var offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size;
+
+            for (var i = this._lastMeasuredIndex + 1; i <= index; i++) {
+                var size = this._cellSizeGetter(i);
+
+                if (size == null || isNaN(size)) {
+                    continue;
+                }
+
+                this._cellSizeAndPositionData[i] = {
+                    offset: offset,
+                    size: size
+                };
+
+                offset += size;
+            }
+
+            this._lastMeasuredIndex = index;
+        }
+        return this._cellSizeAndPositionData[index];
+    },
+
+    getSizeAndPositionOfLastMeasuredCell: function () {
+        return this._lastMeasuredIndex >= 0
+            ? this._cellSizeAndPositionData[this._lastMeasuredIndex]
+            : {
+            offset: 0,
+            size: 0
+        }
+    },
+
+    getTotalSize: function () {
+        var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
+        return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize
+    },
+
+    getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) {
+        var datum = this.getSizeAndPositionOfCell(targetIndex);
+        var maxOffset = datum.offset;
+        var minOffset = maxOffset - containerSize + datum.size;
+
+        var idealOffset;
+
+        switch (align) {
+            case 'start':
+                idealOffset = maxOffset;
+                break;
+            case 'end':
+                idealOffset = minOffset;
+                break;
+            case 'center':
+                idealOffset = maxOffset - ((containerSize - datum.size) / 2);
+                break;
+            default:
+                idealOffset = Math.max(minOffset, Math.min(maxOffset, currentOffset));
+                break;
+        }
+
+        var totalSize = this.getTotalSize();
+
+        return Math.max(0, Math.min(totalSize - containerSize, idealOffset));
+    },
+
+    getVisibleCellRange: function (containerSize, offset) {
+        var totalSize = this.getTotalSize();
+
+        if (totalSize === 0) {
+            return {}
+        }
+
+        var maxOffset = offset + containerSize;
+        var start = this._findNearestCell(offset);
+
+        var datum = this.getSizeAndPositionOfCell(start);
+        offset = datum.offset + datum.size;
+
+        var stop = start;
+
+        while (offset < maxOffset && stop < this._cellCount - 1) {
+            stop++;
+            offset += this.getSizeAndPositionOfCell(stop).size;
+        }
+
+        return {
+            start: start,
+            stop: stop
+        }
+    },
+
+    resetCell: function (index) {
+        this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1)
+    },
+
+    _binarySearch: function (high, low, offset) {
+        var middle;
+        var currentOffset;
+
+        while (low <= high) {
+            middle = low + Math.floor((high - low) / 2);
+            currentOffset = this.getSizeAndPositionOfCell(middle).offset;
+
+            if (currentOffset === offset) {
+                return middle;
+            } else if (currentOffset < offset) {
+                low = middle + 1;
+            } else if (currentOffset > offset) {
+                high = middle - 1;
+            }
+        }
+
+        if (low > 0) {
+            return low - 1;
+        }
+    },
+
+    _exponentialSearch: function (index, offset) {
+        var interval = 1;
+
+        while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) {
+            index += interval;
+            interval *= 2;
+        }
+
+        return this._binarySearch(Math.min(index, this._cellCount - 1), Math.floor(index / 2), offset);
+    },
+
+    _findNearestCell: function (offset) {
+        if (isNaN(offset)) {
+            return;
+        }
+
+        offset = Math.max(0, offset);
+
+        var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
+        var lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex);
+
+        if (lastMeasuredCellSizeAndPosition.offset >= offset) {
+            return this._binarySearch(lastMeasuredIndex, 0, offset);
+        } else {
+            return this._exponentialSearch(lastMeasuredIndex, offset);
+        }
+    }
+};
+
+BI.ScalingCellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) {
+    this._cellSizeAndPositionManager = new BI.CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize);
+    this._maxScrollSize = maxScrollSize || 10000000
+};
+
+BI.ScalingCellSizeAndPositionManager.prototype = {
+    constructor: BI.ScalingCellSizeAndPositionManager,
+
+    configure: function () {
+        this._cellSizeAndPositionManager.configure.apply(this._cellSizeAndPositionManager, arguments);
+    },
+
+    getCellCount: function () {
+        return this._cellSizeAndPositionManager.getCellCount()
+    },
+
+    getEstimatedCellSize: function () {
+        return this._cellSizeAndPositionManager.getEstimatedCellSize()
+    },
+
+    getLastMeasuredIndex: function () {
+        return this._cellSizeAndPositionManager.getLastMeasuredIndex()
+    },
+
+    getOffsetAdjustment: function (containerSize, offset) {
+        var totalSize = this._cellSizeAndPositionManager.getTotalSize();
+        var safeTotalSize = this.getTotalSize();
+        var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize);
+
+        return Math.round(offsetPercentage * (safeTotalSize - totalSize));
+    },
+
+    getSizeAndPositionOfCell: function (index) {
+        return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index);
+    },
+
+    getSizeAndPositionOfLastMeasuredCell: function () {
+        return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell();
+    },
+
+    getTotalSize: function () {
+        return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize());
+    },
+
+    getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) {
+        currentOffset = this._safeOffsetToOffset(containerSize, currentOffset);
+
+        var offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex);
+
+        return this._offsetToSafeOffset(containerSize, offset);
+    },
+
+    getVisibleCellRange: function (containerSize, offset) {
+        offset = this._safeOffsetToOffset(containerSize, offset);
+
+        return this._cellSizeAndPositionManager.getVisibleCellRange(containerSize, offset);
+    },
+
+    resetCell: function (index) {
+        this._cellSizeAndPositionManager.resetCell(index)
+    },
+
+    _getOffsetPercentage: function (containerSize, offset, totalSize) {
+        return totalSize <= containerSize
+            ? 0
+            : offset / (totalSize - containerSize)
+    },
+
+    _offsetToSafeOffset: function (containerSize, offset) {
+        var totalSize = this._cellSizeAndPositionManager.getTotalSize();
+        var safeTotalSize = this.getTotalSize();
+
+        if (totalSize === safeTotalSize) {
+            return offset;
+        } else {
+            var offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize);
+
+            return Math.round(offsetPercentage * (safeTotalSize - containerSize));
+        }
+    },
+
+    _safeOffsetToOffset: function (containerSize, offset) {
+        var totalSize = this._cellSizeAndPositionManager.getTotalSize();
+        var safeTotalSize = this.getTotalSize();
+
+        if (totalSize === safeTotalSize) {
+            return offset;
+        } else {
+            var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize);
+
+            return Math.round(offsetPercentage * (totalSize - containerSize));
+        }
+    }
+};/**
+ * 汉字拼音索引
+ */
+;
+!(function () {
+    var _ChineseFirstPY = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBR"
+        + "CFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZ"
+        + "YRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZ"
+        + "ZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZN"
+        + "TYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJ"
+        + "KQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXK"
+        + "WYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLLSDJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSD"
+        + "CJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHN"
+        + "GPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZ"
+        + "SZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGX"
+        + "XZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTT"
+        + "TKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDK"
+        + "HNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCM"
+        + "BJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZH"
+        + "QKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJ"
+        + "SZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHH"
+        + "ARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKK"
+        + "BXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJ"
+        + "QFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQY"
+        + "TLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZ"
+        + "SQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDP"
+        + "JHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLR"
+        + "DTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBM"
+        + "YHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJ"
+        + "HKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQ"
+        + "HHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZK"
+        + "DDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCS"
+        + "ZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCX"
+        + "TCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYGHBFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZ"
+        + "QAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKT"
+        + "CSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLK"
+        + "QUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZ"
+        + "RNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWLSDQYS"
+        + "JTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHL"
+        + "LQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQ"
+        + "XRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLL"
+        + "BNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJ"
+        + "MHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFF"
+        + "YTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQ"
+        + "XSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJH"
+        + "FXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLW"
+        + "TGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQY"
+        + "BKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLT"
+        + "YXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQY"
+        + "WRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTM"
+        + "LRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTY"
+        + "NXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXC"
+        + "HXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSL"
+        + "LLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYLSDCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXS"
+        + "XNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLSDLDLLBJCYXJZMLHLJDX"
+        + "YYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTY"
+        + "YMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHK"
+        + "ZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYG"
+        + "ZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQ"
+        + "STDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQ"
+        + "XQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXB"
+        + "QKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSL"
+        + "DLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSS"
+        + "NXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWB"
+        + "ZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZ"
+        + "QPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGW"
+        + "SGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJH"
+        + "CLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPK"
+        + "YGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDK"
+        + "NTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYS"
+        + "XDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRB"
+        + "CQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKX"
+        + "WYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYY"
+        + "ZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJ"
+        + "BZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQY"
+        + "QQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXY"
+        + "SZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXC"
+        + "QQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQT"
+        + "TFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJ"
+        + "CJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXW"
+        + "WGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSR"
+        + "NQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXH"
+        + "LHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJ"
+        + "ZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLG"
+        + "YJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDF"
+        + "QTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLFFLGSKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZ"
+        + "ZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYE"
+        + "BHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMC"
+        + "LLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFY"
+        + "WHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZY"
+        + "ZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMS"
+        + "TPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZML"
+        + "LJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJ"
+        + "ZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJM"
+        + "KMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQX"
+        + "YJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQT"
+        + "MYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZM"
+        + "CYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZH"
+        + "HXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJE"
+        + "CXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLL"
+        + "XDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZE"
+        + "AWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJ"
+        + "YHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHL"
+        + "RMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPN"
+        + "HMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQ"
+        + "DCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY";
+
+    //此处收录了375个多音字,数据来自于http://www.51window.net/page/pinyin
+    var oMultiDiff = {
+        "19969": "DZ",
+        "19975": "WM",
+        "19988": "QJ",
+        "20048": "YL",
+        "20056": "SC",
+        "20060": "NM",
+        "20094": "QG",
+        "20127": "QJ",
+        "20167": "QC",
+        "20193": "YG",
+        "20250": "KH",
+        "20256": "ZC",
+        "20282": "SC",
+        "20285": "QJG",
+        "20291": "TD",
+        "20314": "YD",
+        "20340": "NE",
+        "20375": "TD",
+        "20389": "YJ",
+        "20391": "CZ",
+        "20415": "PB",
+        "20446": "YS",
+        "20447": "SQ",
+        "20504": "TC",
+        "20608": "KG",
+        "20854": "QJ",
+        "20857": "ZC",
+        "20911": "PF",
+        "20504": "TC",
+        "20608": "KG",
+        "20854": "QJ",
+        "20857": "ZC",
+        "20911": "PF",
+        "20985": "AW",
+        "21032": "PB",
+        "21048": "XQ",
+        "21049": "SC",
+        "21089": "YS",
+        "21119": "JC",
+        "21242": "SB",
+        "21273": "SC",
+        "21305": "YP",
+        "21306": "QO",
+        "21330": "ZC",
+        "21333": "SDC",
+        "21345": "QK",
+        "21378": "CA",
+        "21397": "SC",
+        "21414": "XS",
+        "21442": "SC",
+        "21477": "JG",
+        "21480": "TD",
+        "21484": "ZS",
+        "21494": "YX",
+        "21505": "YX",
+        "21512": "HG",
+        "21523": "XH",
+        "21537": "PB",
+        "21542": "PF",
+        "21549": "KH",
+        "21571": "E",
+        "21574": "DA",
+        "21588": "TD",
+        "21589": "O",
+        "21618": "ZC",
+        "21621": "KHA",
+        "21632": "ZJ",
+        "21654": "KG",
+        "21679": "LKG",
+        "21683": "KH",
+        "21710": "A",
+        "21719": "YH",
+        "21734": "WOE",
+        "21769": "A",
+        "21780": "WN",
+        "21804": "XH",
+        "21834": "A",
+        "21899": "ZD",
+        "21903": "RN",
+        "21908": "WO",
+        "21939": "ZC",
+        "21956": "SA",
+        "21964": "YA",
+        "21970": "TD",
+        "22003": "A",
+        "22031": "JG",
+        "22040": "XS",
+        "22060": "ZC",
+        "22066": "ZC",
+        "22079": "MH",
+        "22129": "XJ",
+        "22179": "XA",
+        "22237": "NJ",
+        "22244": "TD",
+        "22280": "JQ",
+        "22300": "YH",
+        "22313": "XW",
+        "22331": "YQ",
+        "22343": "YJ",
+        "22351": "PH",
+        "22395": "DC",
+        "22412": "TD",
+        "22484": "PB",
+        "22500": "PB",
+        "22534": "ZD",
+        "22549": "DH",
+        "22561": "PB",
+        "22612": "TD",
+        "22771": "KQ",
+        "22831": "HB",
+        "22841": "JG",
+        "22855": "QJ",
+        "22865": "XQ",
+        "23013": "ML",
+        "23081": "WM",
+        "23487": "SX",
+        "23558": "QJ",
+        "23561": "YW",
+        "23586": "YW",
+        "23614": "YW",
+        "23615": "SN",
+        "23631": "PB",
+        "23646": "ZS",
+        "23663": "ZT",
+        "23673": "YG",
+        "23762": "TD",
+        "23769": "ZS",
+        "23780": "QJ",
+        "23884": "QK",
+        "24055": "XH",
+        "24113": "DC",
+        "24162": "ZC",
+        "24191": "GA",
+        "24273": "QJ",
+        "24324": "NL",
+        "24377": "TD",
+        "24378": "QJ",
+        "24439": "PF",
+        "24554": "ZS",
+        "24683": "TD",
+        "24694": "WE",
+        "24733": "LK",
+        "24925": "TN",
+        "25094": "ZG",
+        "25100": "XQ",
+        "25103": "XH",
+        "25153": "PB",
+        "25170": "PB",
+        "25179": "KG",
+        "25203": "PB",
+        "25240": "ZS",
+        "25282": "FB",
+        "25303": "NA",
+        "25324": "KG",
+        "25341": "ZY",
+        "25373": "WZ",
+        "25375": "XJ",
+        "25384": "A",
+        "25457": "A",
+        "25528": "SD",
+        "25530": "SC",
+        "25552": "TD",
+        "25774": "ZC",
+        "25874": "ZC",
+        "26044": "YW",
+        "26080": "WM",
+        "26292": "PB",
+        "26333": "PB",
+        "26355": "ZY",
+        "26366": "CZ",
+        "26397": "ZC",
+        "26399": "QJ",
+        "26415": "ZS",
+        "26451": "SB",
+        "26526": "ZC",
+        "26552": "JG",
+        "26561": "TD",
+        "26588": "JG",
+        "26597": "CZ",
+        "26629": "ZS",
+        "26638": "YL",
+        "26646": "XQ",
+        "26653": "KG",
+        "26657": "XJ",
+        "26727": "HG",
+        "26894": "ZC",
+        "26937": "ZS",
+        "26946": "ZC",
+        "26999": "KJ",
+        "27099": "KJ",
+        "27449": "YQ",
+        "27481": "XS",
+        "27542": "ZS",
+        "27663": "ZS",
+        "27748": "TS",
+        "27784": "SC",
+        "27788": "ZD",
+        "27795": "TD",
+        "27812": "O",
+        "27850": "PB",
+        "27852": "MB",
+        "27895": "SL",
+        "27898": "PL",
+        "27973": "QJ",
+        "27981": "KH",
+        "27986": "HX",
+        "27994": "XJ",
+        "28044": "YC",
+        "28065": "WG",
+        "28177": "SM",
+        "28267": "QJ",
+        "28291": "KH",
+        "28337": "ZQ",
+        "28463": "TL",
+        "28548": "DC",
+        "28601": "TD",
+        "28689": "PB",
+        "28805": "JG",
+        "28820": "QG",
+        "28846": "PB",
+        "28952": "TD",
+        "28975": "ZC",
+        "29100": "A",
+        "29325": "QJ",
+        "29575": "SL",
+        "29602": "FB",
+        "30010": "TD",
+        "30044": "CX",
+        "30058": "PF",
+        "30091": "YSP",
+        "30111": "YN",
+        "30229": "XJ",
+        "30427": "SC",
+        "30465": "SX",
+        "30631": "YQ",
+        "30655": "QJ",
+        "30684": "QJG",
+        "30707": "SD",
+        "30729": "XH",
+        "30796": "LG",
+        "30917": "PB",
+        "31074": "NM",
+        "31085": "JZ",
+        "31109": "SC",
+        "31181": "ZC",
+        "31192": "MLB",
+        "31293": "JQ",
+        "31400": "YX",
+        "31584": "YJ",
+        "31896": "ZN",
+        "31909": "ZY",
+        "31995": "XJ",
+        "32321": "PF",
+        "32327": "ZY",
+        "32418": "HG",
+        "32420": "XQ",
+        "32421": "HG",
+        "32438": "LG",
+        "32473": "GJ",
+        "32488": "TD",
+        "32521": "QJ",
+        "32527": "PB",
+        "32562": "ZSQ",
+        "32564": "JZ",
+        "32735": "ZD",
+        "32793": "PB",
+        "33071": "PF",
+        "33098": "XL",
+        "33100": "YA",
+        "33152": "PB",
+        "33261": "CX",
+        "33324": "BP",
+        "33333": "TD",
+        "33406": "YA",
+        "33426": "WM",
+        "33432": "PB",
+        "33445": "JG",
+        "33486": "ZN",
+        "33493": "TS",
+        "33507": "QJ",
+        "33540": "QJ",
+        "33544": "ZC",
+        "33564": "XQ",
+        "33617": "YT",
+        "33632": "QJ",
+        "33636": "XH",
+        "33637": "YX",
+        "33694": "WG",
+        "33705": "PF",
+        "33728": "YW",
+        "33882": "SR",
+        "34067": "WM",
+        "34074": "YW",
+        "34121": "QJ",
+        "34255": "ZC",
+        "34259": "XL",
+        "34425": "JH",
+        "34430": "XH",
+        "34485": "KH",
+        "34503": "YS",
+        "34532": "HG",
+        "34552": "XS",
+        "34558": "YE",
+        "34593": "ZL",
+        "34660": "YQ",
+        "34892": "XH",
+        "34928": "SC",
+        "34999": "QJ",
+        "35048": "PB",
+        "35059": "SC",
+        "35098": "ZC",
+        "35203": "TQ",
+        "35265": "JX",
+        "35299": "JX",
+        "35782": "SZ",
+        "35828": "YS",
+        "35830": "E",
+        "35843": "TD",
+        "35895": "YG",
+        "35977": "MH",
+        "36158": "JG",
+        "36228": "QJ",
+        "36426": "XQ",
+        "36466": "DC",
+        "36710": "JC",
+        "36711": "ZYG",
+        "36767": "PB",
+        "36866": "SK",
+        "36951": "YW",
+        "37034": "YX",
+        "37063": "XH",
+        "37218": "ZC",
+        "37325": "ZC",
+        "38063": "PB",
+        "38079": "TD",
+        "38085": "QY",
+        "38107": "DC",
+        "38116": "TD",
+        "38123": "YD",
+        "38224": "HG",
+        "38241": "XTC",
+        "38271": "ZC",
+        "38415": "YE",
+        "38426": "KH",
+        "38461": "YD",
+        "38463": "AE",
+        "38466": "PB",
+        "38477": "XJ",
+        "38518": "YT",
+        "38551": "WK",
+        "38585": "ZC",
+        "38704": "XS",
+        "38739": "LJ",
+        "38761": "GJ",
+        "38808": "SQ",
+        "39048": "JG",
+        "39049": "XJ",
+        "39052": "HG",
+        "39076": "CZ",
+        "39271": "XT",
+        "39534": "TD",
+        "39552": "TD",
+        "39584": "PB",
+        "39647": "SB",
+        "39730": "LG",
+        "39748": "TPB",
+        "40109": "ZQ",
+        "40479": "ND",
+        "40516": "HG",
+        "40536": "HG",
+        "40583": "QJ",
+        "40765": "YQ",
+        "40784": "QJ",
+        "40840": "YK",
+        "40863": "QJG"
+    };
+
+    var _checkPYCh = function (ch) {
+        var uni = ch.charCodeAt(0);
+        // 如果不在汉字处理范围之内,返回原字符,也可以调用自己的处理函数
+        if (uni > 40869 || uni < 19968)
+            return ch; // dealWithOthers(ch);
+        return (oMultiDiff[uni] ? oMultiDiff[uni] : (_ChineseFirstPY.charAt(uni - 19968)));
+    };
+
+    var _mkPYRslt = function (arr) {
+        var arrRslt = [""], k;
+        for (var i = 0, len = arr.length; i < len; i++) {
+            var str = arr[i];
+            var strlen = str.length;
+            if (strlen == 1) {
+                for (k = 0; k < arrRslt.length; k++) {
+                    arrRslt[k] += str;
+                }
+            } else {
+                var tmpArr = arrRslt.slice(0);
+                arrRslt = [];
+                for (k = 0; k < strlen; k++) {
+                    // 复制一个相同的arrRslt
+                    var tmp = tmpArr.slice(0);
+                    // 把当前字符str[k]添加到每个元素末尾
+                    for (var j = 0; j < tmp.length; j++) {
+                        tmp[j] += str.charAt(k);
+                    }
+                    // 把复制并修改后的数组连接到arrRslt上
+                    arrRslt = arrRslt.concat(tmp);
+                }
+            }
+        }
+        return arrRslt.join("").toLowerCase();
+    };
+
+    _.extend(BI, {
+        makeFirstPY: function (str) {
+            if (typeof (str) != "string")
+                return '' + str;
+            var arrResult = []; // 保存中间结果的数组
+            for (var i = 0, len = str.length; i < len; i++) {
+                // 获得unicode码
+                var ch = str.charAt(i);
+                // 检查该unicode码是否在处理范围之内,在则返回该码对映汉字的拼音首字母,不在则调用其它函数处理
+                arrResult.push(_checkPYCh(ch));
+            }
+            // 处理arrResult,返回所有可能的拼音首字母串数组
+            return _mkPYRslt(arrResult);
+        }
+    });
+})();/**
+ * Detect Element Resize.
+ * Forked in order to guard against unsafe 'window' and 'document' references.
+ *
+ * https://github.com/sdecima/javascript-detect-element-resize
+ * Sebastian Decima
+ *
+ * version: 0.5.3
+ **/
+!(function () {
+    // Check `document` and `window` in case of server-side rendering
+    var _window
+    if (typeof window !== 'undefined') {
+        _window = window
+    } else if (typeof self !== 'undefined') {
+        _window = self
+    } else {
+        _window = this
+    }
+
+    var attachEvent = typeof document !== 'undefined' && document.attachEvent;
+    var stylesCreated = false;
+
+    if (!attachEvent) {
+        var requestFrame = (function () {
+            var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame ||
+                function (fn) {
+                    return _window.setTimeout(fn, 20);
+                };
+            return function (fn) {
+                return raf(fn);
+            };
+        })();
+
+        var cancelFrame = (function () {
+            var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame ||
+                _window.clearTimeout;
+            return function (id) {
+                return cancel(id);
+            };
+        })();
+
+        var resetTriggers = function (element) {
+            var triggers = element.__resizeTriggers__,
+                expand = triggers.firstElementChild,
+                contract = triggers.lastElementChild,
+                expandChild = expand.firstElementChild;
+            contract.scrollLeft = contract.scrollWidth;
+            contract.scrollTop = contract.scrollHeight;
+            expandChild.style.width = expand.offsetWidth + 1 + 'px';
+            expandChild.style.height = expand.offsetHeight + 1 + 'px';
+            expand.scrollLeft = expand.scrollWidth;
+            expand.scrollTop = expand.scrollHeight;
+        };
+
+        var checkTriggers = function (element) {
+            return element.offsetWidth !== element.__resizeLast__.width ||
+                element.offsetHeight !== element.__resizeLast__.height;
+        }
+
+        var scrollListener = function (e) {
+            var element = this;
+            resetTriggers(this);
+            if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
+            this.__resizeRAF__ = requestFrame(function () {
+                if (checkTriggers(element)) {
+                    element.__resizeLast__.width = element.offsetWidth;
+                    element.__resizeLast__.height = element.offsetHeight;
+                    element.__resizeListeners__.forEach(function (fn) {
+                        fn.call(element, e);
+                    });
+                }
+            });
+        };
+
+        /* Detect CSS Animations support to detect element display/re-attach */
+        var animation = false,
+            animationstring = 'animation',
+            keyframeprefix = '',
+            animationstartevent = 'animationstart',
+            domPrefixes = 'Webkit Moz O ms'.split(' '),
+            startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
+            pfx = '';
+        {
+            var elm = document.createElement('fakeelement');
+            if (elm.style.animationName !== undefined) {
+                animation = true;
+            }
+
+            if (animation === false) {
+                for (var i = 0; i < domPrefixes.length; i++) {
+                    if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
+                        pfx = domPrefixes[i];
+                        animationstring = pfx + 'Animation';
+                        keyframeprefix = '-' + pfx.toLowerCase() + '-';
+                        animationstartevent = startEvents[i];
+                        animation = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        var animationName = 'resizeanim';
+        var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
+        var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
+    }
+
+    var createStyles = function () {
+        if (!stylesCreated) {
+            //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
+            var css = (animationKeyframes ? animationKeyframes : '') +
+                    '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
+                    '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
+                head = document.head || document.getElementsByTagName('head')[0],
+                style = document.createElement('style');
+
+            style.type = 'text/css';
+            if (style.styleSheet) {
+                style.styleSheet.cssText = css;
+            } else {
+                style.appendChild(document.createTextNode(css));
+            }
+
+            head.appendChild(style);
+            stylesCreated = true;
+        }
+    }
+
+    var addResizeListener = function (element, fn) {
+        if (attachEvent) element.attachEvent('onresize', fn);
+        else {
+            if (!element.__resizeTriggers__) {
+                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
+                createStyles();
+                element.__resizeLast__ = {};
+                element.__resizeListeners__ = [];
+                (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
+                element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
+                    '<div class="contract-trigger"></div>';
+                element.appendChild(element.__resizeTriggers__);
+                resetTriggers(element);
+                element.addEventListener('scroll', scrollListener, true);
+
+                /* Listen for a css animation to detect element display/re-attach */
+                animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function (e) {
+                    if (e.animationName === animationName)
+                        resetTriggers(element);
+                });
+            }
+            element.__resizeListeners__.push(fn);
+        }
+    };
+
+    var removeResizeListener = function (element, fn) {
+        if (attachEvent) element.detachEvent('onresize', fn);
+        else {
+            element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
+            if (!element.__resizeListeners__.length) {
+                element.removeEventListener('scroll', scrollListener, true);
+                element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
+            }
+        }
+    }
+
+    BI.ResizeDetector = {
+        addResizeListener: function (widget, fn) {
+            addResizeListener(widget.element[0], fn);
+        },
+        removeResizeListener: function (widget, fn) {
+            removeResizeListener(widget.element[0], fn);
+        }
+    };
+}());
+;
+(function () {
+    function defaultComparator(a, b) {
+        return a < b;
+    }
+
+    BI.Heap = function (items, comparator) {
+        this._items = items || [];
+        this._size = this._items.length;
+        this._comparator = comparator || defaultComparator;
+        this._heapify();
+    };
+
+    BI.Heap.prototype = {
+        constructor: BI.Heap,
+        empty: function () {
+            return this._size === 0;
+        },
+
+        pop: function () {
+            if (this._size === 0) {
+                return;
+            }
+
+            var elt = this._items[0];
+
+            var lastElt = this._items.pop();
+            this._size--;
+
+            if (this._size > 0) {
+                this._items[0] = lastElt;
+                this._sinkDown(0);
+            }
+
+            return elt;
+        },
+
+        push: function (item) {
+            this._items[this._size++] = item;
+            this._bubbleUp(this._size - 1);
+        },
+
+        size: function () {
+            return this._size;
+        },
+
+        peek: function () {
+            if (this._size === 0) {
+                return;
+            }
+
+            return this._items[0];
+        },
+
+        _heapify: function () {
+            for (var index = Math.floor((this._size + 1) / 2); index >= 0; index--) {
+                this._sinkDown(index);
+            }
+        },
+
+        _bubbleUp: function (index) {
+            var elt = this._items[index];
+            while (index > 0) {
+                var parentIndex = Math.floor((index + 1) / 2) - 1;
+                var parentElt = this._items[parentIndex];
+
+                // if parentElt < elt, stop
+                if (this._comparator(parentElt, elt)) {
+                    return;
+                }
+
+                // swap
+                this._items[parentIndex] = elt;
+                this._items[index] = parentElt;
+                index = parentIndex;
+            }
+        },
+
+        _sinkDown: function (index) {
+            var elt = this._items[index];
+
+            while (true) {
+                var leftChildIndex = 2 * (index + 1) - 1;
+                var rightChildIndex = 2 * (index + 1);
+                var swapIndex = -1;
+
+                if (leftChildIndex < this._size) {
+                    var leftChild = this._items[leftChildIndex];
+                    if (this._comparator(leftChild, elt)) {
+                        swapIndex = leftChildIndex;
+                    }
+                }
+
+                if (rightChildIndex < this._size) {
+                    var rightChild = this._items[rightChildIndex];
+                    if (this._comparator(rightChild, elt)) {
+                        if (swapIndex === -1 ||
+                            this._comparator(rightChild, this._items[swapIndex])) {
+                            swapIndex = rightChildIndex;
+                        }
+                    }
+                }
+
+                // if we don't have a swap, stop
+                if (swapIndex === -1) {
+                    return;
+                }
+
+                this._items[index] = this._items[swapIndex];
+                this._items[swapIndex] = elt;
+                index = swapIndex;
+            }
+        }
+    }
+})();
+;(function () {
+    var clamp = function (min, value, max) {
+        if (value < min) {
+            return min;
+        }
+        if (value > max) {
+            return max;
+        }
+        return value;
+    };
+
+    var BUFFER_ROWS = 5;
+    var NO_ROWS_SCROLL_RESULT = {
+        index: 0,
+        offset: 0,
+        position: 0,
+        contentHeight: 0
+    };
+
+    BI.TableScrollHelper = function (rowCount,
+                                     defaultRowHeight,
+                                     viewportHeight,
+                                     rowHeightGetter) {
+        this._rowOffsets = BI.PrefixIntervalTree.uniform(rowCount, defaultRowHeight);
+        this._storedHeights = new Array(rowCount);
+        for (var i = 0; i < rowCount; ++i) {
+            this._storedHeights[i] = defaultRowHeight;
+        }
+        this._rowCount = rowCount;
+        this._position = 0;
+        this._contentHeight = rowCount * defaultRowHeight;
+        this._defaultRowHeight = defaultRowHeight;
+        this._rowHeightGetter = rowHeightGetter ?
+            rowHeightGetter : function () {
+            return defaultRowHeight
+        };
+        this._viewportHeight = viewportHeight;
+
+        this._updateHeightsInViewport(0, 0);
+    };
+
+    BI.TableScrollHelper.prototype = {
+        constructor: BI.TableScrollHelper,
+        setRowHeightGetter: function (rowHeightGetter) {
+            this._rowHeightGetter = rowHeightGetter;
+        },
+
+        setViewportHeight: function (viewportHeight) {
+            this._viewportHeight = viewportHeight;
+        },
+
+        getContentHeight: function () {
+            return this._contentHeight;
+        },
+
+        _updateHeightsInViewport: function (firstRowIndex,
+                                            firstRowOffset) {
+            var top = firstRowOffset;
+            var index = firstRowIndex;
+            while (top <= this._viewportHeight && index < this._rowCount) {
+                this._updateRowHeight(index);
+                top += this._storedHeights[index];
+                index++;
+            }
+        },
+
+        _updateHeightsAboveViewport: function (firstRowIndex) {
+            var index = firstRowIndex - 1;
+            while (index >= 0 && index >= firstRowIndex - BUFFER_ROWS) {
+                var delta = this._updateRowHeight(index);
+                this._position += delta;
+                index--;
+            }
+        },
+
+        _updateRowHeight: function (rowIndex) {
+            if (rowIndex < 0 || rowIndex >= this._rowCount) {
+                return 0;
+            }
+            var newHeight = this._rowHeightGetter(rowIndex);
+            if (newHeight !== this._storedHeights[rowIndex]) {
+                var change = newHeight - this._storedHeights[rowIndex];
+                this._rowOffsets.set(rowIndex, newHeight);
+                this._storedHeights[rowIndex] = newHeight;
+                this._contentHeight += change;
+                return change;
+            }
+            return 0;
+        },
+
+        getRowPosition: function (rowIndex) {
+            this._updateRowHeight(rowIndex);
+            return this._rowOffsets.sumUntil(rowIndex);
+        },
+
+        scrollBy: function (delta) {
+            if (this._rowCount === 0) {
+                return NO_ROWS_SCROLL_RESULT;
+            }
+            var firstRow = this._rowOffsets.greatestLowerBound(this._position);
+            firstRow = clamp(firstRow, 0, Math.max(this._rowCount - 1, 0));
+            var firstRowPosition = this._rowOffsets.sumUntil(firstRow);
+            var rowIndex = firstRow;
+            var position = this._position;
+
+            var rowHeightChange = this._updateRowHeight(rowIndex);
+            if (firstRowPosition !== 0) {
+                position += rowHeightChange;
+            }
+            var visibleRowHeight = this._storedHeights[rowIndex] -
+                (position - firstRowPosition);
+
+            if (delta >= 0) {
+
+                while (delta > 0 && rowIndex < this._rowCount) {
+                    if (delta < visibleRowHeight) {
+                        position += delta;
+                        delta = 0;
+                    } else {
+                        delta -= visibleRowHeight;
+                        position += visibleRowHeight;
+                        rowIndex++;
+                    }
+                    if (rowIndex < this._rowCount) {
+                        this._updateRowHeight(rowIndex);
+                        visibleRowHeight = this._storedHeights[rowIndex];
+                    }
+                }
+            } else if (delta < 0) {
+                delta = -delta;
+                var invisibleRowHeight = this._storedHeights[rowIndex] - visibleRowHeight;
+
+                while (delta > 0 && rowIndex >= 0) {
+                    if (delta < invisibleRowHeight) {
+                        position -= delta;
+                        delta = 0;
+                    } else {
+                        position -= invisibleRowHeight;
+                        delta -= invisibleRowHeight;
+                        rowIndex--;
+                    }
+                    if (rowIndex >= 0) {
+                        var change = this._updateRowHeight(rowIndex);
+                        invisibleRowHeight = this._storedHeights[rowIndex];
+                        position += change;
+                    }
+                }
+            }
+
+            var maxPosition = this._contentHeight - this._viewportHeight;
+            position = clamp(position, 0, maxPosition);
+            this._position = position;
+            var firstRowIndex = this._rowOffsets.greatestLowerBound(position);
+            firstRowIndex = clamp(firstRowIndex, 0, Math.max(this._rowCount - 1, 0));
+            firstRowPosition = this._rowOffsets.sumUntil(firstRowIndex);
+            var firstRowOffset = firstRowPosition - position;
+
+            this._updateHeightsInViewport(firstRowIndex, firstRowOffset);
+            this._updateHeightsAboveViewport(firstRowIndex);
+
+            return {
+                index: firstRowIndex,
+                offset: firstRowOffset,
+                position: this._position,
+                contentHeight: this._contentHeight
+            };
+        },
+
+        _getRowAtEndPosition: function (rowIndex) {
+            // We need to update enough rows above the selected one to be sure that when
+            // we scroll to selected position all rows between first shown and selected
+            // one have most recent heights computed and will not resize
+            this._updateRowHeight(rowIndex);
+            var currentRowIndex = rowIndex;
+            var top = this._storedHeights[currentRowIndex];
+            while (top < this._viewportHeight && currentRowIndex >= 0) {
+                currentRowIndex--;
+                if (currentRowIndex >= 0) {
+                    this._updateRowHeight(currentRowIndex);
+                    top += this._storedHeights[currentRowIndex];
+                }
+            }
+            var position = this._rowOffsets.sumTo(rowIndex) - this._viewportHeight;
+            if (position < 0) {
+                position = 0;
+            }
+            return position;
+        },
+
+        scrollTo: function (position) {
+            if (this._rowCount === 0) {
+                return NO_ROWS_SCROLL_RESULT;
+            }
+            if (position <= 0) {
+                // If position less than or equal to 0 first row should be fully visible
+                // on top
+                this._position = 0;
+                this._updateHeightsInViewport(0, 0);
+
+                return {
+                    index: 0,
+                    offset: 0,
+                    position: this._position,
+                    contentHeight: this._contentHeight
+                };
+            } else if (position >= this._contentHeight - this._viewportHeight) {
+                // If position is equal to or greater than max scroll value, we need
+                // to make sure to have bottom border of last row visible.
+                var rowIndex = this._rowCount - 1;
+                position = this._getRowAtEndPosition(rowIndex);
+            }
+            this._position = position;
+
+            var firstRowIndex = this._rowOffsets.greatestLowerBound(position);
+            firstRowIndex = clamp(firstRowIndex, 0, Math.max(this._rowCount - 1, 0));
+            var firstRowPosition = this._rowOffsets.sumUntil(firstRowIndex);
+            var firstRowOffset = firstRowPosition - position;
+
+            this._updateHeightsInViewport(firstRowIndex, firstRowOffset);
+            this._updateHeightsAboveViewport(firstRowIndex);
+
+            return {
+                index: firstRowIndex,
+                offset: firstRowOffset,
+                position: this._position,
+                contentHeight: this._contentHeight
+            };
+        },
+
+        /**
+         * Allows to scroll to selected row with specified offset. It always
+         * brings that row to top of viewport with that offset
+         */
+        scrollToRow: function (rowIndex, offset) {
+            rowIndex = clamp(rowIndex, 0, Math.max(this._rowCount - 1, 0));
+            offset = clamp(offset, -this._storedHeights[rowIndex], 0);
+            var firstRow = this._rowOffsets.sumUntil(rowIndex);
+            return this.scrollTo(firstRow - offset);
+        },
+
+        /**
+         * Allows to scroll to selected row by bringing it to viewport with minimal
+         * scrolling. This that if row is fully visible, scroll will not be changed.
+         * If top border of row is above top of viewport it will be scrolled to be
+         * fully visible on the top of viewport. If the bottom border of row is
+         * below end of viewport, it will be scrolled up to be fully visible on the
+         * bottom of viewport.
+         */
+        scrollRowIntoView: function (rowIndex) {
+            rowIndex = clamp(rowIndex, 0, Math.max(this._rowCount - 1, 0));
+            var rowBegin = this._rowOffsets.sumUntil(rowIndex);
+            var rowEnd = rowBegin + this._storedHeights[rowIndex];
+            if (rowBegin < this._position) {
+                return this.scrollTo(rowBegin);
+            } else if (this._position + this._viewportHeight < rowEnd) {
+                var position = this._getRowAtEndPosition(rowIndex);
+                return this.scrollTo(position);
+            }
+            return this.scrollTo(this._position);
+        }
+    };
+
+})();
+// Data structure that allows to store values and assign positions to them
+// in a way to minimize changing positions of stored values when new ones are
+// added or when some values are replaced. Stored elements are alwasy assigned
+// a consecutive set of positoins startin from 0 up to count of elements less 1
+// Following actions can be executed
+// * get position assigned to given value (null if value is not stored)
+// * create new entry for new value and get assigned position back
+// * replace value that is furthest from specified value range with new value
+//   and get it's position back
+// All operations take amortized log(n) time where n is number of elements in
+// the set.
+BI.IntegerBufferSet = function () {
+    this._valueToPositionMap = {};
+    this._size = 0;
+    this._smallValues = new BI.Heap(
+        [], // Initial data in the heap
+        this._smallerComparator
+    );
+    this._largeValues = new BI.Heap(
+        [], // Initial data in the heap
+        this._greaterComparator
+    );
+
+};
+
+BI.IntegerBufferSet.prototype = {
+    constructor: BI.IntegerBufferSet,
+    getSize: function () /*number*/ {
+        return this._size;
+    },
+
+    getValuePosition: function (/*number*/ value) /*?number*/ {
+        if (this._valueToPositionMap[value] === undefined) {
+            return null;
+        }
+        return this._valueToPositionMap[value];
+    },
+
+    getNewPositionForValue: function (/*number*/ value) /*number*/ {
+        var newPosition = this._size;
+        this._size++;
+        this._pushToHeaps(newPosition, value);
+        this._valueToPositionMap[value] = newPosition;
+        return newPosition;
+    },
+
+    replaceFurthestValuePosition: function (/*number*/ lowValue,
+                                            /*number*/ highValue,
+                                            /*number*/ newValue) /*?number*/ {
+        this._cleanHeaps();
+        if (this._smallValues.empty() || this._largeValues.empty()) {
+            // Threre are currently no values stored. We will have to create new
+            // position for this value.
+            return null;
+        }
+
+        var minValue = this._smallValues.peek().value;
+        var maxValue = this._largeValues.peek().value;
+        if (minValue >= lowValue && maxValue <= highValue) {
+            // All values currently stored are necessary, we can't reuse any of them.
+            return null;
+        }
+
+        var valueToReplace;
+        if (lowValue - minValue > maxValue - highValue) {
+            // minValue is further from provided range. We will reuse it's position.
+            valueToReplace = minValue;
+            this._smallValues.pop();
+        } else {
+            valueToReplace = maxValue;
+            this._largeValues.pop();
+        }
+        var position = this._valueToPositionMap[valueToReplace];
+        delete this._valueToPositionMap[valueToReplace];
+        this._valueToPositionMap[newValue] = position;
+        this._pushToHeaps(position, newValue);
+
+        return position;
+    },
+
+    _pushToHeaps: function (/*number*/ position, /*number*/ value) {
+        var element = {
+            position: position,
+            value:value
+        };
+        // We can reuse the same object in both heaps, because we don't mutate them
+        this._smallValues.push(element);
+        this._largeValues.push(element);
+    },
+
+    _cleanHeaps: function () {
+        // We not usually only remove object from one heap while moving value.
+        // Here we make sure that there is no stale data on top of heaps.
+        this._cleanHeap(this._smallValues);
+        this._cleanHeap(this._largeValues);
+        var minHeapSize =
+            Math.min(this._smallValues.size(), this._largeValues.size());
+        var maxHeapSize =
+            Math.max(this._smallValues.size(), this._largeValues.size());
+        if (maxHeapSize > 10 * minHeapSize) {
+            // There are many old values in one of heaps. We nned to get rid of them
+            // to not use too avoid memory leaks
+            this._recreateHeaps();
+        }
+    },
+
+    _recreateHeaps: function () {
+        var sourceHeap = this._smallValues.size() < this._largeValues.size() ?
+            this._smallValues :
+            this._largeValues;
+        var newSmallValues = new Heap(
+            [], // Initial data in the heap
+            this._smallerComparator
+        );
+        var newLargeValues = new Heap(
+            [], // Initial datat in the heap
+            this._greaterComparator
+        );
+        while (!sourceHeap.empty()) {
+            var element = sourceHeap.pop();
+            // Push all stil valid elements to new heaps
+            if (this._valueToPositionMap[element.value] !== undefined) {
+                newSmallValues.push(element);
+                newLargeValues.push(element);
+            }
+        }
+        this._smallValues = newSmallValues;
+        this._largeValues = newLargeValues;
+    },
+
+    _cleanHeap: function (/*object*/ heap) {
+        while (!heap.empty() &&
+        this._valueToPositionMap[heap.peek().value] === undefined) {
+            heap.pop();
+        }
+    },
+
+    _smallerComparator: function (/*object*/ lhs, /*object*/ rhs) /*boolean*/ {
+        return lhs.value < rhs.value;
+    },
+
+    _greaterComparator: function (/*object*/ lhs, /*object*/ rhs) /*boolean*/ {
+        return lhs.value > rhs.value;
+    }
+};
+;
+!(function () {
+    BI.LinkHashMap = function () {
+        this.array = [];
+        this.map = {};
+    };
+    BI.LinkHashMap.prototype = {
+        constructor: BI.LinkHashMap,
+        has: function (key) {
+            if (key in this.map) {
+                return true;
+            }
+            return false;
+        },
+
+        add: function (key, value) {
+            if (typeof key == 'undefined') {
+                return;
+            }
+            if (key in this.map) {
+                this.map[key] = value;
+            } else {
+                this.array.push(key);
+                this.map[key] = value;
+            }
+        },
+
+        remove: function (key) {
+            if (key in this.map) {
+                delete this.map[key];
+                for (var i = 0; i < this.array.length; i++) {
+                    if (this.array[i] == key) {
+                        this.array.splice(i, 1);
+                        break;
+                    }
+                }
+            }
+        },
+
+        size: function () {
+            return this.array.length;
+        },
+
+        each: function (fn, scope) {
+            var scope = scope || window;
+            var fn = fn || null;
+            if (fn == null || typeof (fn) != "function") {
+                return;
+            }
+            for (var i = 0; i < this.array.length; i++) {
+                var key = this.array[i];
+                var value = this.map[key];
+                var re = fn.call(scope, key, value, i, this.array, this.map);
+                if (re == false) {
+                    break;
+                }
+            }
+        },
+
+        get: function (key) {
+            return this.map[key];
+        },
+
+        toArray: function () {
+            var array = [];
+            this.each(function (key, value) {
+                array.push(value);
+            })
+            return array;
+        }
+    }
+})();window.BI = window.BI || {};
+
+$.extend(BI, {
+    $defaultImport: function (options) {
+        var config = $.extend({
+            op: 'resource',
+            path: null,
+            type: null,
+            must: false
+        }, options);
+        config.url = FR.servletURL + '?op=' + config.op + '&resource=' + config.path;
+        this.$import(config.url, config.type,config.must);
+    },
+    $import: function () {
+        var _LOADED = {}; // alex:保存加载过的
+        function loadReady(src, must) {
+            var $scripts = $("head script");
+            $.each($scripts, function (i, item) {
+                if (item.src.indexOf(src) != -1) {
+                    _LOADED[src] = true;
+                }
+            });
+            var $links = $("head link");
+            $.each($links, function (i, item) {
+                if (item.href.indexOf(src) != -1 && must) {
+                    _LOADED[src] = false;
+                    $(item).remove();
+                }
+            });
+        }
+
+        // must=true 强行加载
+        return function (src, ext, must) {
+            loadReady(src, must);
+            // alex:如果已经加载过了的,直接return
+            if (_LOADED[src] === true) {
+                return;
+            }
+            if (ext === 'css') {
+                var link = document.createElement('link');
+                link.rel = 'stylesheet';
+                link.type = 'text/css';
+                link.href = src;
+                var head = document.getElementsByTagName('head')[0];
+                head.appendChild(link);
+                _LOADED[src] = true;
+            } else {
+                // alex:这里用同步调用的方式,必须等待ajax完成
+                $.ajax({
+                    url: src,
+                    dataType: "script", // alex:指定dataType为script,jquery会帮忙做globalEval的事情
+                    async: false,
+                    cache: true,
+                    complete: function (res, status) {
+                        /*
+                         * alex:发现jquery会很智能地判断一下返回的数据类型是不是script,然后做一个globalEval
+                         * 所以当status为success时就不需要再把其中的内容加到script里面去了
+                         */
+                        if (status == 'success') {
+                            _LOADED[src] = true;
+                        }
+                    }
+                })
+            }
+        }
+    }()
+});;
+!(function () {
+    BI.LRU = function (limit) {
+        this.size = 0;
+        this.limit = limit;
+        this.head = this.tail = undefined;
+        this._keymap = {};
+    };
+
+    var p = BI.LRU.prototype;
+
+    p.put = function (key, value) {
+        var removed;
+        if (this.size === this.limit) {
+            removed = this.shift();
+        }
+
+        var entry = this.get(key, true);
+        if (!entry) {
+            entry = {
+                key: key
+            };
+            this._keymap[key] = entry;
+            if (this.tail) {
+                this.tail.newer = entry;
+                entry.older = this.tail
+            } else {
+                this.head = entry
+            }
+            this.tail = entry;
+            this.size++;
+        }
+        entry.value = value;
+
+        return removed;
+    };
+
+    p.shift = function () {
+        var entry = this.head;
+        if (entry) {
+            this.head = this.head.newer;
+            this.head.older = undefined;
+            entry.newer = entry.older = undefined;
+            this._keymap[entry.key] = undefined;
+            this.size--;
+        }
+        return entry;
+    };
+
+
+    p.get = function (key, returnEntry) {
+        var entry = this._keymap[key];
+        if (entry === undefined) return;
+        if (entry === this.tail) {
+            return returnEntry
+                ? entry
+                : entry.value
+        }
+        // HEAD--------------TAIL
+        //   <.older   .newer>
+        //  <--- add direction --
+        //   A  B  C  <D>  E
+        if (entry.newer) {
+            if (entry === this.head) {
+                this.head = entry.newer
+            }
+            entry.newer.older = entry.older; // C <-- E.
+        }
+        if (entry.older) {
+            entry.older.newer = entry.newer; // C. --> E
+        }
+        entry.newer = undefined; // D --x
+        entry.older = this.tail; // D. --> E
+        if (this.tail) {
+            this.tail.newer = entry; // E. <-- D
+        }
+        this.tail = entry;
+        return returnEntry
+            ? entry
+            : entry.value
+    };
+})();;
+!(function () {
+    var MD5 = function (hexcase) {
+        this.hexcase = !hexcase ? 0 : 1;
+        /* hex output format. 0 - lowercase; 1 - uppercase */
+        this.b64pad = "";
+        /* base-64 pad character. "=" for strict RFC compliance */
+        this.chrsz = 8;
+        /* bits per input character. 8 - ASCII; 16 - Unicode */
+    };
+
+    /*
+     * These are the functions you'll usually want to call
+     * They take string arguments and return either hex or base-64 encoded strings
+     */
+    MD5.prototype.hex_md5 = function (s) {
+        return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz));
+    };
+
+    MD5.prototype.hex_md5_salt = function (s) {
+        var md5ed = this.hex_md5(s);
+
+        var items1 = [];
+        var items2 = [];
+        for (var i = 0; i < md5ed.length; i++) {
+            if (i % 2 === 0) {
+                items1.push(md5ed.charAt(i));
+            } else {
+                items2.push(md5ed.charAt(i));
+            }
+        }
+        var result = ":" + items1.join("") + items2.join("");
+        return result;
+    };
+
+    MD5.prototype.b64_md5 = function (s) {
+        return this.binl2b64(this.core_md5(this.str2binl(s), s.length * this.chrsz));
+    };
+
+    MD5.prototype.hex_hmac_md5 = function (key, data) {
+        return this.binl2hex(this.core_hmac_md5(key, data));
+    };
+
+    MD5.prototype.b64_hmac_md5 = function (key, data) {
+        return this.binl2b64(this.core_hmac_md5(key, data));
+    };
+
+    /* Backwards compatibility - same as hex_md5() */
+    MD5.prototype.calcMD5 = function (s) {
+        return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz));
+    };
+
+    MD5.prototype.core_md5 = function (x, len) {
+        /* append padding */
+        x[len >> 5] |= 0x80 << ((len) % 32);
+        x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+        var a = 1732584193;
+        var b = -271733879;
+        var c = -1732584194;
+        var d = 271733878;
+
+        for (var i = 0; i < x.length; i += 16) {
+            var olda = a;
+            var oldb = b;
+            var oldc = c;
+            var oldd = d;
+
+            a = this.md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
+            d = this.md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
+            c = this.md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
+            b = this.md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
+            a = this.md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
+            d = this.md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
+            c = this.md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
+            b = this.md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
+            a = this.md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
+            d = this.md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
+            c = this.md5_ff(c, d, a, b, x[i + 10], 17, -42063);
+            b = this.md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
+            a = this.md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
+            d = this.md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
+            c = this.md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
+            b = this.md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
+
+            a = this.md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
+            d = this.md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
+            c = this.md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
+            b = this.md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
+            a = this.md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
+            d = this.md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
+            c = this.md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
+            b = this.md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
+            a = this.md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
+            d = this.md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
+            c = this.md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
+            b = this.md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
+            a = this.md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
+            d = this.md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
+            c = this.md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
+            b = this.md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
+
+            a = this.md5_hh(a, b, c, d, x[i + 5], 4, -378558);
+            d = this.md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
+            c = this.md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
+            b = this.md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
+            a = this.md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
+            d = this.md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
+            c = this.md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
+            b = this.md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
+            a = this.md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
+            d = this.md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
+            c = this.md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
+            b = this.md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
+            a = this.md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
+            d = this.md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
+            c = this.md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
+            b = this.md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
+
+            a = this.md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
+            d = this.md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
+            c = this.md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
+            b = this.md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
+            a = this.md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
+            d = this.md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
+            c = this.md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
+            b = this.md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
+            a = this.md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
+            d = this.md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
+            c = this.md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
+            b = this.md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
+            a = this.md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
+            d = this.md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
+            c = this.md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
+            b = this.md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
+
+            a = this.safe_add(a, olda);
+            b = this.safe_add(b, oldb);
+            c = this.safe_add(c, oldc);
+            d = this.safe_add(d, oldd);
+        }
+        return Array(a, b, c, d);
+
+    };
+
+    /*
+     * These functions implement the four basic operations the algorithm uses.
+     */
+    MD5.prototype.md5_cmn = function (q, a, b, x, s, t) {
+        return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s), b);
+    };
+    MD5.prototype.md5_ff = function (a, b, c, d, x, s, t) {
+        return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+    };
+    MD5.prototype.md5_gg = function (a, b, c, d, x, s, t) {
+        return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+    };
+    MD5.prototype.md5_hh = function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(b ^ c ^ d, a, b, x, s, t);
+    };
+    MD5.prototype.md5_ii = function (a, b, c, d, x, s, t) {
+        return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+    };
+
+    /*
+     * Calculate the HMAC-MD5, of a key and some data
+     */
+    MD5.prototype.core_hmac_md5 = function (key, data) {
+        var bkey = this.str2binl(key);
+        if (bkey.length > 16)
+            bkey = this.core_md5(bkey, key.length * this.chrsz);
+
+        var ipad = Array(16), opad = Array(16);
+        for (var i = 0; i < 16; i++) {
+            ipad[i] = bkey[i] ^ 0x36363636;
+            opad[i] = bkey[i] ^ 0x5C5C5C5C;
+        }
+
+        var hash = this.core_md5(ipad.concat(this.str2binl(data)), 512 + data.length * this.chrsz);
+        return this.core_md5(opad.concat(hash), 512 + 128);
+    };
+
+    /*
+     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+     * to work around bugs in some JS interpreters.
+     */
+    MD5.prototype.safe_add = function (x, y) {
+        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+        return (msw << 16) | (lsw & 0xFFFF);
+    };
+
+    /*
+     * Bitwise rotate a 32-bit number to the left.
+     */
+    MD5.prototype.bit_rol = function (num, cnt) {
+        return (num << cnt) | (num >>> (32 - cnt));
+    };
+
+    /*
+     * Convert a string to an array of little-endian words
+     * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+     */
+    MD5.prototype.str2binl = function (str) {
+        var bin = Array();
+        var mask = (1 << this.chrsz) - 1;
+        for (var i = 0; i < str.length * this.chrsz; i += this.chrsz)
+            bin[i >> 5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i % 32);
+        return bin;
+    };
+
+    /*
+     * Convert an array of little-endian words to a hex string.
+     */
+    MD5.prototype.binl2hex = function (binarray) {
+        var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+        var str = "";
+        for (var i = 0; i < binarray.length * 4; i++) {
+            str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF)
+                + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
+        }
+        return str;
+    };
+
+    /*
+     * Convert an array of little-endian words to a base-64 string
+     */
+    MD5.prototype.binl2b64 = function (binarray) {
+        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        var str = "";
+        for (var i = 0; i < binarray.length * 4; i += 3) {
+            var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
+                | (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
+                | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
+            for (var j = 0; j < 4; j++) {
+                if (i * 8 + j * 6 > binarray.length * 32)
+                    str += this.b64pad;
+                else
+                    str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
+            }
+        }
+        return str;
+    };
+    BI.MD5 = new MD5();
+})();//线段树
+;(function () {
+    var parent = function (node) {
+        return Math.floor(node / 2);
+    };
+
+    var Int32Array = window.Int32Array || function (size) {
+            var xs = [];
+            for (var i = size - 1; i >= 0; --i) {
+                xs[i] = 0;
+            }
+            return xs;
+        };
+
+    var ceilLog2 = function (x) {
+        var y = 1;
+        while (y < x) {
+            y *= 2;
+        }
+        return y;
+    };
+
+    BI.PrefixIntervalTree = function (xs) {
+        this._size = xs.length;
+        this._half = ceilLog2(this._size);
+        this._heap = new Int32Array(2 * this._half);
+
+        var i;
+        for (i = 0; i < this._size; ++i) {
+            this._heap[this._half + i] = xs[i];
+        }
+
+        for (i = this._half - 1; i > 0; --i) {
+            this._heap[i] = this._heap[2 * i] + this._heap[2 * i + 1];
+        }
+    };
+
+    BI.PrefixIntervalTree.prototype = {
+        constructor: BI.PrefixIntervalTree,
+        set: function (index, value) {
+            var node = this._half + index;
+            this._heap[node] = value;
+
+            node = parent(node);
+            for (; node !== 0; node = parent(node)) {
+                this._heap[node] =
+                    this._heap[2 * node] + this._heap[2 * node + 1];
+            }
+        },
+
+        get: function (index) {
+            var node = this._half + index;
+            return this._heap[node];
+        },
+
+        getSize: function () {
+            return this._size;
+        },
+
+        /**
+         * get(0) + get(1) + ... + get(end - 1).
+         */
+        sumUntil: function (end) {
+            if (end === 0) {
+                return 0;
+            }
+
+            var node = this._half + end - 1;
+            var sum = this._heap[node];
+            for (; node !== 1; node = parent(node)) {
+                if (node % 2 === 1) {
+                    sum += this._heap[node - 1];
+                }
+            }
+
+            return sum;
+        },
+
+        /**
+         * get(0) + get(1) + ... + get(inclusiveEnd).
+         */
+        sumTo: function (inclusiveEnd) {
+            return this.sumUntil(inclusiveEnd + 1);
+        },
+
+        /**
+         * sum get(begin) + get(begin + 1) + ... + get(end - 1).
+         */
+        sum: function (begin, end) {
+            return this.sumUntil(end) - this.sumUntil(begin);
+        },
+
+        /**
+         * Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or
+         * -1 if no such i exists.
+         */
+        greatestLowerBound: function (t) {
+            if (t < 0) {
+                return -1;
+            }
+
+            var node = 1;
+            if (this._heap[node] <= t) {
+                return this._size;
+            }
+
+            while (node < this._half) {
+                var leftSum = this._heap[2 * node];
+                if (t < leftSum) {
+                    node = 2 * node;
+                } else {
+                    node = 2 * node + 1;
+                    t -= leftSum;
+                }
+            }
+
+            return node - this._half;
+        },
+
+        /**
+         * Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or
+         * -1 if no such i exists.
+         */
+        greatestStrictLowerBound: function (t) {
+            if (t <= 0) {
+                return -1;
+            }
+
+            var node = 1;
+            if (this._heap[node] < t) {
+                return this._size;
+            }
+
+            while (node < this._half) {
+                var leftSum = this._heap[2 * node];
+                if (t <= leftSum) {
+                    node = 2 * node;
+                } else {
+                    node = 2 * node + 1;
+                    t -= leftSum;
+                }
+            }
+
+            return node - this._half;
+        },
+
+        /**
+         * Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or
+         * size + 1 if no such i exists.
+         */
+        leastUpperBound: function (t) {
+            return this.greatestStrictLowerBound(t) + 1;
+        },
+
+        /**
+         * Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or
+         * size + 1 if no such i exists.
+         */
+        leastStrictUpperBound: function (t) {
+            return this.greatestLowerBound(t) + 1;
+        }
+    };
+
+    BI.PrefixIntervalTree.uniform = function (size, initialValue) {
+        var xs = [];
+        for (var i = size - 1; i >= 0; --i) {
+            xs[i] = initialValue;
+        }
+
+        return new BI.PrefixIntervalTree(xs);
+    };
+
+    BI.PrefixIntervalTree.empty = function () {
+        return BI.PrefixIntervalTree.uniform(size, 0);
+    };
+
+})();
+;
+!(function () {
+    BI.Queue = function (capacity) {
+        this.capacity = capacity;
+        this.array = [];
+    };
+    BI.Queue.prototype = {
+        constructor: BI.Queue,
+
+        contains: function (v) {
+            return this.array.contains(v);
+        },
+
+        indexOf: function (v) {
+            return this.array.contains(v);
+        },
+
+        getElementByIndex: function(index) {
+            return this.array[index];
+        },
+
+        push: function (v) {
+            this.array.push(v);
+            if (this.capacity && this.array.length > this.capacity) {
+                this.array.shift();
+            }
+        },
+
+        pop: function () {
+            this.array.pop();
+        },
+
+        shift: function () {
+            this.array.shift();
+        },
+
+        unshift: function (v) {
+            this.array.unshift(v);
+            if (this.capacity && this.array.length > this.capacity) {
+                this.array.pop();
+            }
+        },
+
+        remove: function (v) {
+            this.array.remove(v);
+        },
+        
+        splice: function() {
+            this.array.splice.apply(this.array, arguments);  
+        },
+        
+        slice: function() {
+            this.array.slice.apply(this.array, arguments);    
+        },
+        
+        size: function () {
+            return this.array.length;
+        },
+
+        each: function (fn, scope) {
+            var scope = scope || window;
+            var fn = fn || null;
+            if (fn == null || typeof (fn) != "function") {
+                return;
+            }
+            for (var i = 0; i < this.array.length; i++) {
+                var re = fn.call(scope, i, this.array[i], this.array);
+                if (re == false) {
+                    break;
+                }
+            }
+        },
+
+        toArray: function () {
+            return this.array;
+        },
+
+        fromArray: function (array) {
+            var self = this;
+            BI.each(array, function (i, v) {
+                self.push(v);
+            })
+        },
+
+        clear: function () {
+            this.array.clear();
+        }
+    }
+})();!(function () {
+    var Section = function (height, width, x, y) {
+        this.height = height;
+        this.width = width;
+        this.x = x;
+        this.y = y;
+
+        this._indexMap = {};
+        this._indices = [];
+    };
+
+    Section.prototype = {
+        constructor: Section,
+        addCellIndex: function (index) {
+            if (!this._indexMap[index]) {
+                this._indexMap[index] = true;
+                this._indices.push(index);
+            }
+        },
+
+        getCellIndices: function () {
+            return this._indices
+        }
+    };
+
+    var SECTION_SIZE = 100;
+    BI.SectionManager = function (sectionSize) {
+        this._sectionSize = sectionSize || SECTION_SIZE;
+        this._cellMetadata = [];
+        this._sections = {};
+    };
+
+    BI.SectionManager.prototype = {
+        constructor: BI.SectionManager,
+        getCellIndices: function (height, width, x, y) {
+            var indices = {};
+
+            BI.each(this.getSections(height, width, x, y), function (i, section) {
+                BI.each(section.getCellIndices(), function (j, index) {
+                    indices[index] = index
+                })
+            });
+
+            return BI.map(BI.keys(indices), function (i, index) {
+                return indices[index]
+            });
+        },
+
+        getCellMetadata: function (index) {
+            return this._cellMetadata[index];
+        },
+
+        getSections: function (height, width, x, y) {
+            var sectionXStart = Math.floor(x / this._sectionSize);
+            var sectionXStop = Math.floor((x + width - 1) / this._sectionSize);
+            var sectionYStart = Math.floor(y / this._sectionSize);
+            var sectionYStop = Math.floor((y + height - 1) / this._sectionSize);
+
+            var sections = [];
+
+            for (var sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) {
+                for (var sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) {
+                    var key = sectionX + "." + sectionY;
+
+                    if (!this._sections[key]) {
+                        this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize)
+                    }
+
+                    sections.push(this._sections[key])
+                }
+            }
+
+            return sections
+        },
+
+        getTotalSectionCount: function () {
+            return BI.size(this._sections);
+        },
+
+        registerCell: function (cellMetadatum, index) {
+            this._cellMetadata[index] = cellMetadatum;
+
+            BI.each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) {
+                section.addCellIndex(index);
+            });
+        }
+    }
+})();if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {
+
+} else {
+    Set = function () {
+        this.set = {}
+    };
+    Set.prototype.has = function (key) {
+        return this.set[key] !== undefined;
+    };
+    Set.prototype.add = function (key) {
+        this.set[key] = 1
+    };
+    Set.prototype.clear = function () {
+        this.set = {}
+    };
+};
+(function () {
+    var clamp = function (value, min, max) {
+        if (value < min) {
+            return min;
+        }
+        if (value > max) {
+            return max;
+        }
+        return value;
+    };
+    var MIN_BUFFER_ROWS = 6;
+    var MAX_BUFFER_ROWS = 10;
+
+    BI.TableRowBuffer = function (rowsCount,
+                                  defaultRowHeight,
+                                  viewportHeight,
+                                  rowHeightGetter) {
+        this._bufferSet = new BI.IntegerBufferSet();
+        this._defaultRowHeight = defaultRowHeight;
+        this._viewportRowsBegin = 0;
+        this._viewportRowsEnd = 0;
+        this._maxVisibleRowCount = Math.ceil(viewportHeight / defaultRowHeight) + 1;
+        // this._bufferRowsCount = Math.floor(this._maxVisibleRowCount / 2);
+        this._bufferRowsCount = clamp(
+            Math.floor(this._maxVisibleRowCount / 2),
+            MIN_BUFFER_ROWS,
+            MAX_BUFFER_ROWS
+        );
+        this._rowsCount = rowsCount;
+        this._rowHeightGetter = rowHeightGetter;
+        this._rows = [];
+        this._viewportHeight = viewportHeight;
+
+    };
+    BI.TableRowBuffer.prototype = {
+        constructor: BI.TableRowBuffer,
+
+        getRowsWithUpdatedBuffer: function () {
+            var remainingBufferRows = 2 * this._bufferRowsCount;
+            var bufferRowIndex =
+                Math.max(this._viewportRowsBegin - this._bufferRowsCount, 0);
+            while (bufferRowIndex < this._viewportRowsBegin) {
+                this._addRowToBuffer(
+                    bufferRowIndex,
+                    this._viewportRowsBegin,
+                    this._viewportRowsEnd - 1
+                );
+                bufferRowIndex++;
+                remainingBufferRows--;
+            }
+            bufferRowIndex = this._viewportRowsEnd;
+            while (bufferRowIndex < this._rowsCount && remainingBufferRows > 0) {
+                this._addRowToBuffer(
+                    bufferRowIndex,
+                    this._viewportRowsBegin,
+                    this._viewportRowsEnd - 1
+                );
+                bufferRowIndex++;
+                remainingBufferRows--;
+            }
+            return this._rows;
+        },
+
+        getRows: function (firstRowIndex,
+                           firstRowOffset) {
+            var top = firstRowOffset;
+            var totalHeight = top;
+            var rowIndex = firstRowIndex;
+            var endIndex =
+                Math.min(firstRowIndex + this._maxVisibleRowCount, this._rowsCount);
+
+            this._viewportRowsBegin = firstRowIndex;
+            while (rowIndex < endIndex ||
+            (totalHeight < this._viewportHeight && rowIndex < this._rowsCount)) {
+                this._addRowToBuffer(
+                    rowIndex,
+                    firstRowIndex,
+                    endIndex - 1
+                );
+                totalHeight += this._rowHeightGetter(rowIndex);
+                ++rowIndex;
+                // Store index after the last viewport row as end, to be able to
+                // distinguish when there are no rows rendered in viewport
+                this._viewportRowsEnd = rowIndex;
+            }
+
+            return this._rows;
+        },
+
+        _addRowToBuffer: function (rowIndex,
+                                   firstViewportRowIndex,
+                                   lastViewportRowIndex) {
+            var rowPosition = this._bufferSet.getValuePosition(rowIndex);
+            var viewportRowsCount = lastViewportRowIndex - firstViewportRowIndex + 1;
+            var allowedRowsCount = viewportRowsCount + this._bufferRowsCount * 2;
+            if (rowPosition === null &&
+                this._bufferSet.getSize() >= allowedRowsCount) {
+                rowPosition =
+                    this._bufferSet.replaceFurthestValuePosition(
+                        firstViewportRowIndex,
+                        lastViewportRowIndex,
+                        rowIndex
+                    );
+            }
+            if (rowPosition === null) {
+                // We can't reuse any of existing positions for this row. We have to
+                // create new position
+                rowPosition = this._bufferSet.getNewPositionForValue(rowIndex);
+                this._rows[rowPosition] = rowIndex;
+            } else {
+                // This row already is in the table with rowPosition position or it
+                // can replace row that is in that position
+                this._rows[rowPosition] = rowIndex;
+            }
+        }
+    }
+
+})();
+;
+(function () {
+    BI.Tree = function () {
+        this.root = new BI.Node(BI.UUID());
+    };
+
+    BI.Tree.prototype = {
+        constructor: BI.Tree,
+        addNode: function (node, newNode, index) {
+            if (BI.isNull(newNode)) {
+                this.root.addChild(node, index);
+            } else if (BI.isNull(node)) {
+                this.root.addChild(newNode, index);
+            } else {
+                node.addChild(newNode, index);
+            }
+        },
+
+        isRoot: function (node) {
+            return node === this.root || node.id === this.root.id;
+        },
+
+        getRoot: function () {
+            return this.root;
+        },
+
+        clear: function () {
+            this.root.clear();
+        },
+
+        initTree: function (nodes) {
+            var self = this;
+            this.clear();
+            var queue = [];
+            BI.each(nodes, function (i, node) {
+                var n = new BI.Node(node);
+                n.set("data", node);
+                self.addNode(n);
+                queue.push(n);
+            });
+            while (!BI.isEmpty(queue)) {
+                var parent = queue.shift();
+                var node = parent.get("data");
+                BI.each(node.children, function (i, child) {
+                    var n = new BI.Node(child);
+                    n.set("data", child);
+                    queue.push(n);
+                    self.addNode(parent, n);
+                })
+            }
+        },
+
+        _toJSON: function (node) {
+            var self = this;
+            var children = [];
+            BI.each(node.getChildren(), function (i, child) {
+                children.push(self._toJSON(child));
+            });
+            return BI.extend({
+                id: node.id
+            }, BI.deepClone(node.get("data")), (children.length > 0 ? {
+                children: children
+            } : {}));
+        },
+
+        toJSON: function (node) {
+            var self = this, result = [];
+            BI.each((node || this.root).getChildren(), function (i, child) {
+                result.push(self._toJSON(child));
+            });
+            return result;
+        },
+
+        _toJSONWithNode: function (node) {
+            var self = this;
+            var children = [];
+            BI.each(node.getChildren(), function (i, child) {
+                children.push(self._toJSONWithNode(child));
+            });
+            return BI.extend({
+                id: node.id
+            }, BI.deepClone(node.get("data")), {
+                node: node
+            }, (children.length > 0 ? {
+                children: children
+            } : {}));
+        },
+
+        toJSONWithNode: function (node) {
+            var self = this, result = [];
+            BI.each((node || this.root).getChildren(), function (i, child) {
+                result.push(self._toJSONWithNode(child));
+            });
+            return result;
+        },
+
+        search: function (root, target, param) {
+            if (!(root instanceof BI.Node)) {
+                return arguments.callee.apply(this, [this.root, root, target]);
+            }
+            var self = this, next = null;
+
+            if (BI.isNull(target)) {
+                return null;
+            }
+            if (BI.isEqual(root[param || "id"], target)) {
+                return root;
+            }
+            BI.any(root.getChildren(), function (i, child) {
+                next = self.search(child, target, param);
+                if (null !== next) {
+                    return true;
+                }
+            });
+            return next;
+        },
+
+        _traverse: function (node, callback) {
+            var queue = [];
+            queue.push(node);
+            while (!BI.isEmpty(queue)) {
+                var temp = queue.shift();
+                var b = callback && callback(temp);
+                if (b === false) {
+                    break;
+                }
+                if (b === true) {
+                    continue;
+                }
+                if (temp != null) {
+                    queue = queue.concat(temp.getChildren());
+                }
+            }
+        },
+
+        traverse: function (callback) {
+            this._traverse(this.root, callback);
+        },
+
+        _recursion: function (node, route, callback) {
+            var self = this;
+            return BI.every(node.getChildren(), function (i, child) {
+                var next = BI.clone(route);
+                next.push(child.id);
+                var b = callback && callback(child, next);
+                if (b === false) {
+                    return false;
+                }
+                if (b === true) {
+                    return true;
+                }
+                return self._recursion(child, next, callback);
+            });
+        },
+
+        recursion: function (callback) {
+            this._recursion(this.root, [], callback);
+        },
+
+        inOrderTraverse: function (callback) {
+            this._inOrderTraverse(this.root, callback);
+        },
+
+        //中序遍历(递归)
+        _inOrderTraverse: function (node, callback) {
+            if (node != null) {
+                this._inOrderTraverse(node.getLeft());
+                callback && callback(node);
+                this._inOrderTraverse(node.getRight());
+            }
+        },
+
+        //中序遍历(非递归)
+        nrInOrderTraverse: function (callback) {
+
+            var stack = [];
+            var node = this.root;
+            while (node != null || !BI.isEmpty(stack)) {
+                while (node != null) {
+                    stack.push(node);
+                    node = node.getLeft();
+                }
+                node = stack.pop();
+                callback && callback(node);
+                node = node.getRight();
+            }
+        },
+
+        preOrderTraverse: function (callback) {
+            this._preOrderTraverse(this.root, callback);
+        },
+
+        //先序遍历(递归)
+        _preOrderTraverse: function (node, callback) {
+            if (node != null) {
+                callback && callback(node);
+                this._preOrderTraverse(node.getLeft());
+                this._preOrderTraverse(node.getRight());
+            }
+        },
+
+        //先序遍历(非递归)
+        nrPreOrderTraverse: function (callback) {
+
+            var stack = [];
+            var node = this.root;
+
+            while (node != null || !BI.isEmpty(stack)) {
+
+                while (node != null) {
+                    callback && callback(node);
+                    stack.push(node);
+                    node = node.getLeft();
+                }
+                node = stack.pop();
+                node = node.getRight();
+            }
+        },
+
+        postOrderTraverse: function (callback) {
+            this._postOrderTraverse(this.root, callback);
+        },
+
+        //后序遍历(递归)
+        _postOrderTraverse: function (node, callback) {
+            if (node != null) {
+                this._postOrderTraverse(node.getLeft());
+                this._postOrderTraverse(node.getRight());
+                callback && callback(node);
+            }
+        },
+
+        //后续遍历(非递归)
+        nrPostOrderTraverse: function (callback) {
+
+            var stack = [];
+            var node = this.root;
+            var preNode = null;//表示最近一次访问的节点
+
+            while (node != null || !BI.isEmpty(stack)) {
+
+                while (node != null) {
+                    stack.push(node);
+                    node = node.getLeft();
+                }
+
+                node = BI.last(stack);
+
+                if (node.getRight() == null || node.getRight() == preNode) {
+                    callback && callback(node);
+                    node = stack.pop();
+                    preNode = node;
+                    node = null;
+                } else {
+                    node = node.getRight();
+                }
+            }
+        }
+    };
+
+    BI.Node = function (id) {
+        if (BI.isObject(id)) {
+            BI.extend(this, id);
+        } else {
+            this.id = id;
+        }
+        this.clear.apply(this, arguments);
+    };
+
+    BI.Node.prototype = {
+        constructor: BI.Node,
+
+        set: function (key, value) {
+            if (BI.isObject(key)) {
+                BI.extend(this, key);
+                return;
+            }
+            this[key] = value;
+        },
+
+        get: function (key) {
+            return this[key];
+        },
+
+        isLeaf: function () {
+            return BI.isEmpty(this.children);
+        },
+
+        getChildren: function () {
+            return this.children;
+        },
+
+        getChildrenLength: function () {
+            return this.children.length;
+        },
+
+        getFirstChild: function () {
+            return BI.first(this.children);
+        },
+
+        getLastChild: function () {
+            return BI.last(this.children);
+        },
+
+        setLeft: function (left) {
+            this.left = left;
+        },
+
+        getLeft: function () {
+            return this.left;
+        },
+
+        setRight: function (right) {
+            this.right = right;
+        },
+
+        getRight: function () {
+            return this.right;
+        },
+
+        setParent: function (parent) {
+            this.parent = parent;
+        },
+
+        getParent: function () {
+            return this.parent;
+        },
+
+        getChild: function (index) {
+            return this.children[index];
+        },
+
+        getChildIndex: function (id) {
+            return BI.findIndex(this.children, function (i, ch) {
+                return ch.get("id") === id;
+            });
+        },
+
+        removeChild: function (id) {
+            this.removeChildByIndex(this.getChildIndex(id));
+        },
+
+        removeChildByIndex: function (index) {
+            var before = this.getChild(index - 1);
+            var behind = this.getChild(index + 1);
+            if (before != null) {
+                before.setRight(behind || null);
+            }
+            if (behind != null) {
+                behind.setLeft(before || null);
+            }
+            this.children.splice(index, 1);
+        },
+
+        removeAllChilds: function () {
+            this.children = [];
+        },
+
+        addChild: function (child, index) {
+            var cur = null;
+            if (BI.isUndefined(index)) {
+                cur = this.children.length - 1;
+            } else {
+                cur = index - 1;
+            }
+            child.setParent(this);
+            if (cur >= 0) {
+                this.getChild(cur).setRight(child);
+                child.setLeft(this.getChild(cur));
+            }
+            if (BI.isUndefined(index)) {
+                this.children.push(child);
+            } else {
+                this.children.splice(index, 0, child);
+            }
+        },
+
+        equals: function (obj) {
+            return this === obj || this.id === obj.id;
+        },
+
+        clear: function () {
+            this.parent = null;
+            this.left = null;
+            this.right = null;
+            this.children = [];
+        }
+    };
+
+    BI.extend(BI.Tree, {
+        transformToArrayFormat: function (nodes, pId) {
+            if (!nodes) return [];
+            var r = [];
+            if (BI.isArray(nodes)) {
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    var node = BI.clone(nodes[i]);
+                    node.pId = pId;
+                    delete node.children;
+                    r.push(node);
+                    if (nodes[i]["children"]) {
+                        r = r.concat(BI.Tree.transformToArrayFormat(nodes[i]["children"], node.id));
+                    }
+                }
+            } else {
+                var newNodes = BI.clone(nodes);
+                newNodes.pId = pId;
+                delete newNodes.children;
+                r.push(newNodes);
+                if (nodes["children"]) {
+                    r = r.concat(BI.Tree.transformToArrayFormat(nodes["children"], newNodes.id));
+                }
+            }
+            return r;
+        },
+
+        arrayFormat: function (nodes, pId) {
+            if (!nodes) return [];
+            var r = [];
+            if (BI.isArray(nodes)) {
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    var node = nodes[i];
+                    r.push(node);
+                    if (nodes[i]["children"]) {
+                        r = r.concat(BI.Tree.transformToArrayFormat(nodes[i]["children"], node.id));
+                    }
+                }
+            } else {
+                var newNodes = nodes;
+                r.push(newNodes);
+                if (nodes["children"]) {
+                    r = r.concat(BI.Tree.transformToArrayFormat(nodes["children"], newNodes.id));
+                }
+            }
+            return r;
+        },
+
+        transformToTreeFormat: function (sNodes) {
+            var i, l;
+            if (!sNodes) {
+                return [];
+            }
+
+            if (BI.isArray(sNodes)) {
+                var r = [];
+                var tmpMap = [];
+                for (i = 0, l = sNodes.length; i < l; i++) {
+                    if(BI.isNull(sNodes[i].id)) {
+                        return sNodes;
+                    }
+                    tmpMap[sNodes[i].id] = BI.clone(sNodes[i]);
+                }
+                for (i = 0, l = sNodes.length; i < l; i++) {
+                    if (tmpMap[sNodes[i].pId] && sNodes[i].id != sNodes[i].pId) {
+                        if (!tmpMap[sNodes[i].pId].children) {
+                            tmpMap[sNodes[i].pId].children = [];
+                        }
+                        tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]);
+                    } else {
+                        r.push(tmpMap[sNodes[i].id]);
+                    }
+                    delete tmpMap[sNodes[i].id].pId;
+                }
+                return r;
+            } else {
+                return [sNodes];
+            }
+        }
+    })
+})();//向量操作
+BI.Vector = function (x, y) {
+    this.x = x;
+    this.y = y;
+};
+BI.Vector.prototype = {
+    constructor: BI.Vector,
+    cross: function (v) {
+        return (this.x * v.y - this.y * v.x);
+    },
+    length: function (v) {
+        return (Math.sqrt(this.x * v.x + this.y * v.y));
+    }
+};
+BI.Region = function (x, y, w, h) {
+    this.x = x;
+    this.y = y;
+    this.w = w;
+    this.h = h;
+};
+BI.Region.prototype = {
+    constructor: BI.Region,
+    //判断两个区域是否相交,若相交,则要么顶点互相包含,要么矩形边界(或对角线)相交
+    isIntersects: function (obj) {
+        if (this.isPointInside(obj.x, obj.y) ||
+            this.isPointInside(obj.x + obj.w, obj.y) ||
+            this.isPointInside(obj.x, obj.y + obj.h) ||
+            this.isPointInside(obj.x + obj.w, obj.y + obj.h)) {
+            return true;
+        } else if (obj.isPointInside(this.x, this.y) ||
+            obj.isPointInside(this.x + this.w, this.y) ||
+            obj.isPointInside(this.x, this.y + this.h) ||
+            obj.isPointInside(this.x + this.w, this.y + this.h)) {
+            return true;
+        } else if (obj.x != null && obj.y != null)//判断矩形对角线相交 |v1 X v2||v1 X v3| < 0
+        {
+            var vector1 = new BI.Vector(this.w, this.h);//矩形对角线向量
+            var vector2 = new BI.Vector(obj.x - this.x, obj.y - this.y);
+            var vector3 = new BI.Vector(vector2.x + obj.w, vector2.y + obj.h);
+            if ((vector1.cross(vector2) * vector1.cross(vector3)) < 0) {
+                return true;
+            }
+        }
+        return false;
+    },
+    //判断一个点是否在这个区域内部
+    isPointInside: function (x, y) {
+        if (this.x == null || this.y == null) {
+            return false;
+        }
+        if (x >= this.x && x <= this.x + this.w && y >= this.y && y <= this.y + this.h) {
+            return true;
+        }
+        return false;
+    },
+    //返回区域的重心,因为是矩形所以返回中点
+    getPosition: function () {
+        var pos = [];
+        pos.push(this.x + this.w / 2);
+        pos.push(this.y + this.h / 2);
+        return pos;
+    }
+};;
+!(function (BI) {
+
+    if (BI.isIE()) {
+        XMLSerializer = null;
+        DOMParser = null;
+    }
+
+
+    var XML = {
+        Document: {
+            NodeType: {
+                ELEMENT: 1,
+                ATTRIBUTE: 2,
+                TEXT: 3,
+                CDATA_SECTION: 4,
+                ENTITY_REFERENCE: 5,
+                ENTITY: 6,
+                PROCESSING_INSTRUCTION: 7,
+                COMMENT: 8,
+                DOCUMENT: 9,
+                DOCUMENT_TYPE: 10,
+                DOCUMENT_FRAGMENT: 11,
+                NOTATION: 12
+            }
+        }
+    };
+
+    XML.ResultType = {
+        single: 'single',
+        array: 'array'
+    };
+
+    XML.fromString = function (xmlStr) {
+        try {
+            var parser = new DOMParser();
+            return parser.parseFromString(xmlStr, "text/xml");
+        } catch (e) {
+            var arrMSXML = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0"];
+            for (var i = 0; i < arrMSXML.length; i++) {
+                try {
+                    var xmlDoc = new ActiveXObject(arrMSXML[i]);
+                    xmlDoc.setProperty("SelectionLanguage", "XPath");
+                    xmlDoc.async = false;
+                    xmlDoc.loadXML(xmlStr);
+                    return xmlDoc;
+                } catch (xmlError) {
+                }
+            }
+        }
+    };
+
+    XML.toString = function (xmlNode) {
+        if (!BI.isIE()) {
+            var xmlSerializer = new XMLSerializer();
+            return xmlSerializer.serializeToString(xmlNode);
+        } else
+            return xmlNode.xml;
+    };
+
+    XML.getNSResolver = function (str) {
+        if (!str)
+            return null;
+        var list = str.split(' ');
+        var namespaces = {};
+        for (var i = 0; i < list.length; i++) {
+            var pair = list[i].split('=');
+            var fix = BI.trim(pair[0]).replace("xmlns:", "");
+            namespaces[fix] = BI.trim(pair[1]).replace(/"/g, "").replace(/'/g, "");
+        }
+        return function (prefix) {
+            return namespaces[prefix];
+        };
+    };
+
+    XML.eval = function (context, xpathExp, resultType, namespaces) {
+        if ((BI.isIE() && ('undefined' === typeof(context.selectSingleNode) || 'undefined' === typeof(context.selectNodes)))) {
+            return XML.eval2(context, xpathExp, resultType, namespaces);
+        } else {
+            if (BI.isIE()) {
+                namespaces = namespaces ? namespaces : "";
+                var doc = (context.nodeType == XML.Document.NodeType.DOCUMENT) ? context : context.ownerDocument;
+                doc.setProperty("SelectionNamespaces", namespaces);
+                var result;
+                if (resultType == this.ResultType.single) {
+                    result = context.selectSingleNode(xpathExp);
+                } else {
+                    result = context.selectNodes(xpathExp) || [];
+                }
+                doc.setProperty("SelectionNamespaces", "");
+                return result;
+            } else {
+                var node = context;
+                var xmlDoc = (context.nodeName.indexOf("document") == -1) ? context.ownerDocument : context;
+                var retType = (resultType == this.ResultType.single) ? XPathResult.FIRST_ORDERED_NODE_TYPE : XPathResult.ANY_TYPE;
+                var col = xmlDoc.evaluate(xpathExp, node, XML.getNSResolver(namespaces), retType, null);
+
+                if (retType == XPathResult.FIRST_ORDERED_NODE_TYPE) {
+                    return col.singleNodeValue;
+                } else {
+                    var thisColMemb = col.iterateNext();
+                    var rowsCol = [];
+                    while (thisColMemb) {
+                        rowsCol[rowsCol.length] = thisColMemb;
+                        thisColMemb = col.iterateNext();
+                    }
+                    return rowsCol;
+                }
+            }
+        }
+    };
+
+    XML.eval2 = function (context, xpathExp, resultType, namespaces) {
+        if (resultType !== "single" && resultType !== undefined && resultType !== null) {
+            throw new Error("justep.SimpleXML.eval只支持resultType='single', 不支持" + resultType);
+        }
+
+        if (context === null || context === undefined || xpathExp === null || xpathExp === undefined) {
+            return context;
+        }
+
+        if (context.nodeType == XML.Document.NodeType.DOCUMENT) {
+            context = context.documentElement;
+        }
+
+        var childs, i;
+        if (xpathExp.indexOf("/") != -1) {
+            var items = xpathExp.split("/");
+            var isAbs = xpathExp.substring(0, 1) == "/";
+            for (i = 0; i < items.length; i++) {
+                var item = items[i];
+                if (item === "") {
+                    continue;
+                } else {
+                    var next = null;
+                    var ii = i + 1;
+                    for (; ii < items.length; ii++) {
+                        if (next === null) {
+                            next = items[ii];
+                        } else {
+                            next = next + "/" + items[ii];
+                        }
+                    }
+
+                    if (item == ".") {
+                        return this.eval(context, next, resultType);
+
+                    } else if (item == "..") {
+                        return this.eval2(context.parentNode, next, resultType);
+
+                    } else if (item == "*") {
+                        if (isAbs) {
+                            return this.eval2(context, next, resultType);
+
+                        } else {
+                            childs = context.childNodes;
+                            for (var j = 0; j < childs.length; j++) {
+                                var tmp = this.eval2(childs[j], next, resultType);
+                                if (tmp !== null) {
+                                    return tmp;
+                                }
+                            }
+                            return null;
+                        }
+
+                    } else {
+                        if (isAbs) {
+                            if (context.nodeName == item) {
+                                return this.eval2(context, next, resultType);
+                            } else {
+                                return null;
+                            }
+                        } else {
+                            var child = this.getChildByName(context, item);
+                            if (child !== null) {
+                                return this.eval2(child, next, resultType);
+                            } else {
+                                return null;
+                            }
+
+                        }
+                    }
+
+                }
+            }
+
+            return null;
+
+        } else {
+            if ("text()" == xpathExp) {
+                childs = context.childNodes;
+                for (i = 0; i < childs.length; i++) {
+                    if (childs[i].nodeType == XML.Document.NodeType.TEXT) {
+                        return childs[i];
+                    }
+                }
+                return null;
+            } else {
+                return this.getChildByName(context, xpathExp);
+            }
+        }
+    };
+
+    XML.getChildByName = function (context, name) {
+        if (context === null || context === undefined || name === null || name === undefined) {
+            return null;
+        }
+
+        if (context.nodeType == XML.Document.NodeType.DOCUMENT) {
+            context = context.documentElement;
+        }
+
+        var childs = context.childNodes;
+        for (var i = 0; i < childs.length; i++) {
+            if (childs[i].nodeType == XML.Document.NodeType.ELEMENT && (childs[i].nodeName == name || name == "*")) {
+                return childs[i];
+            }
+        }
+
+        return null;
+    };
+
+    XML.appendChildren = function (context, xpathExp, nodes, isBefore) {
+        nodes = (typeof nodes.length != "undefined") ? nodes : [nodes];
+        var finded = this.eval(context, xpathExp);
+        var count = finded.length;
+        for (var i = 0; i < count; i++) {
+            if (isBefore && finded[i].firstNode) {
+                this._insertBefore(finded[i], nodes, finded[i].firstNode);
+            } else {
+                for (var j = 0; j < nodes.length; j++) {
+                    finded[i].appendChild(nodes[j]);
+                }
+            }
+        }
+        return count;
+    };
+
+    XML.removeNodes = function (context, xpathExp) {
+        var nodes = this.eval(context, xpathExp);
+        for (var i = 0; i < nodes.length; i++) {
+            nodes[i].parentNode.removeChild(nodes[i]);
+        }
+    };
+
+    XML._insertBefore = function (parent, newchildren, refchild) {
+        for (var i = 0; i < newchildren.length; i++) {
+            parent.insertBefore(newchildren[i], refchild);
+        }
+    };
+
+    XML.insertNodes = function (context, xpathExp, nodes, isBefore) {
+        nodes = (typeof nodes.length != "undefined") ? nodes : [nodes];
+        var finded = this.eval(context, xpathExp);
+        var count = finded.length;
+        for (var i = 0; i < count; i++) {
+            var refnode = (isBefore) ? finded[i] : finded[i].nextSibling;
+            this._insertBefore(finded[i].parentNode, nodes, refnode);
+        }
+        return count;
+    };
+
+    XML.replaceNodes = function (context, xpathExp, nodes) {
+        nodes = (typeof nodes.length != "undefined") ? nodes : [nodes];
+        var finded = this.eval(context, xpathExp);
+        var count = finded.length;
+        for (var i = 0; i < count; i++) {
+            var refnode = finded[i];
+            var parent = refnode.parentNode;
+            this._insertBefore(parent, nodes, refnode);
+            parent.removeChild(refnode);
+        }
+        return count;
+    };
+
+    XML.setNodeText = function (context, xpathExp, text) {
+        var finded = this.eval(context, xpathExp, this.ResultType.single);
+        if (finded === null)
+            return;
+        if (finded.nodeType == XML.Document.NodeType.ELEMENT) {
+            var textNode = this.eval(finded, "./text()", this.ResultType.single);
+            if (!textNode) {
+                textNode = finded.ownerDocument.createTextNode("");
+                finded.appendChild(textNode);
+            }
+            textNode.nodeValue = text;
+        } else {
+            finded.nodeValue = text;
+        }
+        return;
+    };
+
+    XML.getNodeText = function (context, xpathExp, defaultValue) {
+        var finded = xpathExp ? this.eval(context, xpathExp, this.ResultType.single) : context;
+        if (finded && (finded.nodeType == XML.Document.NodeType.ELEMENT)) {
+            finded = this.eval(finded, "./text()", this.ResultType.single);
+        }
+        return (finded && finded.nodeValue) ? "" + finded.nodeValue : (defaultValue !== undefined) ? defaultValue : null;
+    };
+
+    XML.Namespaces = {
+        XMLSCHEMA: "http://www.w3.org/2001/XMLSchema#",
+        XMLSCHEMA_STRING: "http://www.w3.org/2001/XMLSchema#String",
+        XMLSCHEMA_LONG: "http://www.w3.org/2001/XMLSchema#Long",
+        XMLSCHEMA_INTEGER: 'http://www.w3.org/2001/XMLSchema#Integer',
+        XMLSCHEMA_FLOAT: 'http://www.w3.org/2001/XMLSchema#Float',
+        XMLSCHEMA_DOUBLE: 'http://www.w3.org/2001/XMLSchema#Double',
+        XMLSCHEMA_DECIMAL: 'http://www.w3.org/2001/XMLSchema#Decimal',
+        XMLSCHEMA_DATE: 'http://www.w3.org/2001/XMLSchema#Date',
+        XMLSCHEMA_TIME: 'http://www.w3.org/2001/XMLSchema#Time',
+        XMLSCHEMA_DATETIME: 'http://www.w3.org/2001/XMLSchema#DateTime',
+        XMLSCHEMA_BOOLEAN: 'http://www.w3.org/2001/XMLSchema#Boolean',
+        XMLSCHEMA_SYMBOL: 'http://www.w3.org/2001/XMLSchema#Symbol',
+        JUSTEPSCHEMA: "http://www.justep.com/xbiz#",
+        RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+        JUSTEP: "http://www.justep.com/x5#",
+        'get': function (type) {
+            type = type ? type.toLowerCase() : "string";
+            if ("string" == type)
+                return XML.Namespaces.XMLSCHEMA_STRING;
+            else if ("integer" == type)
+                return XML.Namespaces.XMLSCHEMA_INTEGER;
+            else if ("long" == type)
+                return XML.Namespaces.XMLSCHEMA_LONG;
+            else if ("float" == type)
+                return XML.Namespaces.XMLSCHEMA_FLOAT;
+            else if ("double" == type)
+                return XML.Namespaces.XMLSCHEMA_DOUBLE;
+            else if ("decimal" == type)
+                return XML.Namespaces.XMLSCHEMA_DECIMAL;
+            else if ("date" == type)
+                return XML.Namespaces.XMLSCHEMA_DATE;
+            else if ("time" == type)
+                return XML.Namespaces.XMLSCHEMA_TIME;
+            else if ("datetime" == type)
+                return XML.Namespaces.XMLSCHEMA_DATETIME;
+            else if ("boolean" == type)
+                return XML.Namespaces.XMLSCHEMA_BOOLEAN;
+        }
+    };
+})(BI);BI.BehaviorFactory = {
+    createBehavior: function(key, options){
+        var behavior;
+        switch (key){
+            case "highlight":
+                behavior = BI.HighlightBehavior;
+                break;
+            case "redmark":
+                behavior = BI.RedMarkBehavior;
+                break;
+        }
+        return new behavior(options);
+    }
+}
+
+/**
+ * guy
+ * 行为控件
+ * @class BI.Behavior
+ * @extends BI.OB
+ */
+BI.Behavior = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.Behavior.superclass._defaultConfig.apply(this, arguments), {
+            rule: function(){return true;}
+        });
+    },
+
+    _init : function() {
+        BI.Behavior.superclass._init.apply(this, arguments);
+
+    },
+
+    doBehavior: function(){
+
+    }
+});/**
+ * 布局容器类
+ * @class BI.Layout
+ * @extends BI.Widget
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Boolean} [options.scrollable=false] 子组件超出容器边界之后是否会出现滚动条
+ * @cfg {Boolean} [options.scrollx=false] 子组件超出容器边界之后是否会出现横向滚动条
+ * @cfg {Boolean} [options.scrolly=false] 子组件超出容器边界之后是否会出现纵向滚动条
+ */
+BI.Layout = BI.inherit(BI.Widget, {
+    props: function () {
+        return {
+            scrollable: null, //true, false, null
+            scrollx: false, //true, false
+            scrolly: false, //true, false
+            items: []
+        };
+    },
+
+    created: function () {
+        this._init4Margin();
+        this._init4Scroll();
+    },
+
+    _init4Margin: function () {
+        if (this.options.top) {
+            this.element.css('top', this.options.top);
+        }
+        if (this.options.left) {
+            this.element.css('left', this.options.left);
+        }
+        if (this.options.bottom) {
+            this.element.css('bottom', this.options.bottom);
+        }
+        if (this.options.right) {
+            this.element.css('right', this.options.right);
+        }
+    },
+
+    _init4Scroll: function () {
+        switch (this.options.scrollable) {
+            case true:
+                this.element.css("overflow", "auto");
+                break;
+            case false:
+                this.element.css("overflow", "hidden");
+                break;
+            default :
+                break;
+        }
+        if (this.options.scrollx) {
+            this.element.css({
+                "overflow-x": "auto",
+                "overflow-y": "hidden"
+            });
+        }
+        if (this.options.scrolly) {
+            this.element.css({
+                "overflow-x": "hidden",
+                "overflow-y": "auto"
+            });
+        }
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w;
+        if (!this.hasWidget(this.getName() + "-" + i)) {
+            w = BI.createWidget(item);
+            this.addWidget(this.getName() + "-" + i, w);
+        } else {
+            w = this.getWidgetByName(this.getName() + "-" + i);
+        }
+        return w;
+    },
+
+    stroke: function (items) {
+        var self = this;
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                self._addElement(i, item);
+            }
+        });
+    },
+
+    populate: function (items) {
+        var self = this;
+        this.options.items = items || [];
+        this.stroke(items);
+    },
+
+    resize: function () {
+
+    },
+
+    /**
+     * 添加一个子组件到容器中
+     * @param {JSON/BI.Widget} item 子组件
+     */
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.element);
+        return w;
+    },
+
+    addItems: function (items) {
+        var self = this;
+        BI.each(items, function (i, item) {
+            self.addItem(item);
+        })
+    },
+
+    getValue: function () {
+        var value = [];
+        BI.each(this._children, function (i, wi) {
+            var v = wi.getValue();
+            v = BI.isArray(v) ? v : [v];
+            value = value.concat(v);
+        });
+        return value;
+    },
+
+    setValue: function (v) {
+        BI.each(this._children, function (i, wi) {
+            wi.setValue(v);
+        })
+    },
+
+    setText: function (v) {
+        BI.each(this._children, function (i, wi) {
+            wi.setText(v);
+        })
+    }
+});
+$.shortcut('bi.layout', BI.Layout);/**
+ * guy
+ * 由一个元素切换到另一个元素的行为
+ * @class BI.Action
+ * @extends BI.OB
+ * @abstract
+ */
+BI.Action = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.Action.superclass._defaultConfig.apply(this, arguments), {
+            src: null,
+            tar: null
+        });
+    },
+
+    _init : function() {
+        BI.Action.superclass._init.apply(this, arguments);
+    },
+
+    actionPerformed: function(src, tar, callback){
+
+    },
+
+    actionBack: function(tar, src, callback){
+
+    }
+});
+
+BI.ActionFactory = {
+    createAction: function(key, options){
+        var action;
+        switch (key){
+            case "show":
+                action = BI.ShowAction;
+                break;
+        }
+        return new action(options);
+    }
+}/**
+ * guy
+ * 由一个元素切换到另一个元素的行为
+ * @class BI.EffectShowAction
+ * @extends BI.Action
+ */
+BI.EffectShowAction = BI.inherit(BI.Action, {
+    _defaultConfig: function() {
+        return BI.extend(BI.EffectShowAction.superclass._defaultConfig.apply(this, arguments), {
+        });
+    },
+
+    _init : function() {
+        BI.EffectShowAction.superclass._init.apply(this, arguments);
+    },
+
+    _checkBrowser: function(){
+        return false;
+//        return !(BI.isFireFox() && parseInt($.browser.version) < 10);
+    },
+
+    actionPerformed: function(src, tar, callback){
+        src = src || this.options.src ,tar = tar || this.options.tar || "body";
+
+        if(this._checkBrowser()) {
+            var transferEl = BI.createWidget({
+                type: "bi.layout",
+                cls: "bi-transfer-temp-el"
+            })
+
+            BI.createWidget({
+                type: "bi.absolute",
+                element: "body",
+                items: [transferEl]
+            })
+
+            transferEl.element.css({
+                width: tar.element.width(),
+                height: tar.element.height(),
+                top: tar.element.offset().top,
+                left: tar.element.offset().left
+            });
+
+            src.element.effect("transfer", {
+                to: transferEl.element,
+                className: "ui-effects-transfer"
+            }, 400, function () {
+                transferEl.destroy();
+                tar && tar.element.show(0, callback);
+            })
+        } else {
+            tar && tar.element.show(0, callback);
+        }
+    },
+
+    actionBack: function(tar, src, callback){
+        src = src || this.options.src || $("body"),tar = tar || this.options.tar;
+        tar && tar.element.hide();
+        if(this._checkBrowser()) {
+            var transferEl = BI.createWidget({
+                type: "bi.layout",
+                cls: "bi-transfer-temp-el"
+            })
+
+            BI.createWidget({
+                type: "bi.absolute",
+                element: "body",
+                items: [transferEl]
+            })
+            transferEl.element.css({
+                width: src.element.width(),
+                height: src.element.height(),
+                top: src.element.offset().top,
+                left: src.element.offset().left
+            });
+
+            tar.element.effect("transfer", {
+                to: transferEl.element,
+                className: "ui-effects-transfer"
+            }, 400, function () {
+                transferEl.destroy();
+                callback && callback();
+            })
+        } else {
+            callback && callback();
+        }
+    }
+});/**
+ * guy
+ * 由一个元素切换到另一个元素的行为
+ * @class BI.ShowAction
+ * @extends BI.Action
+ */
+BI.ShowAction = BI.inherit(BI.Action, {
+    _defaultConfig: function() {
+        return BI.extend(BI.ShowAction.superclass._defaultConfig.apply(this, arguments), {
+        });
+    },
+
+    _init : function() {
+        BI.ShowAction.superclass._init.apply(this, arguments);
+    },
+
+    actionPerformed: function(src, tar, callback){
+        tar = tar || this.options.tar;
+        tar && tar.element.show(0, callback);
+    },
+
+    actionBack: function(tar, src, callback){
+        tar = tar || this.options.tar;
+        tar.element.hide(0, callback);
+    }
+});/**
+ * guy
+ * 由一个元素切换到另一个元素的行为
+ * @class BI.ScaleShowAction
+ * @extends BI.Action
+ * @abstract
+ */
+BI.ScaleShowAction = BI.inherit(BI.Action, {
+    _defaultConfig: function() {
+        return BI.extend(BI.ScaleShowAction.superclass._defaultConfig.apply(this, arguments), {
+        });
+    },
+
+    _init : function() {
+        BI.ScaleShowAction.superclass._init.apply(this, arguments);
+    },
+
+    _checkBrowser: function(){
+        return false;
+//        return !(BI.isFireFox() && parseInt($.browser.version) < 10);
+    },
+
+    actionPerformed: function(src, tar, callback){
+        tar = tar || this.options.tar;
+        this._checkBrowser() ? tar.element.show("scale", {percent:110}, 200, callback) : tar.element.show(0,callback);
+    },
+
+    actionBack : function(tar, src, callback){
+        tar = tar || this.options.tar;
+        this._checkBrowser() ? tar.element.hide("scale", {percent:0}, 200, callback) : tar.element.hide(0,callback);
+    }
+});/**
+ * @class BI.FloatSection
+ * @extends BI.View
+ * @abstract
+ */
+BI.FloatSection = BI.inherit(BI.View, {
+    _init : function() {
+        BI.FloatSection.superclass._init.apply(this, arguments);
+        var self = this;
+        var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"];
+        flatten = BI.makeObject(flatten, true);
+        BI.each(this.constructor.caller.caller.caller.prototype, function (key) {
+            if (flatten[key]) {
+                return;
+            }
+            var f = self[key];
+            if (BI.isFunction(f)) {
+                self[key] = BI.bind(function () {
+                    if (this.model._start === true) {
+                        this._F.push({f: f, arg: arguments});
+                        return;
+                    }
+                    return f.apply(this, arguments);
+                }, self);
+            }
+        })
+    },
+
+    rebuildNorth : function(north) {
+        return true;
+    },
+    rebuildCenter : function(center) {},
+    rebuildSouth : function(south) {
+        return false;
+    },
+    close: function(){
+        this.notifyParentEnd();
+        this.trigger(BI.PopoverSection.EVENT_CLOSE);
+    },
+    end: function(){
+
+    }
+});
+
+/**
+ * 弹出层
+ * @class BI.PopoverSection
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.PopoverSection = BI.inherit(BI.Widget, {
+    _init : function() {
+        BI.PopoverSection.superclass._init.apply(this, arguments);
+    },
+
+    rebuildNorth : function(north) {
+        return true;
+    },
+    rebuildCenter : function(center) {},
+    rebuildSouth : function(south) {
+        return false;
+    },
+    close: function(){
+        this.fireEvent(BI.PopoverSection.EVENT_CLOSE);
+    },
+    end: function(){
+
+    }
+});
+BI.PopoverSection.EVENT_CLOSE = "EVENT_CLOSE";/**
+ * guy
+ *
+ * @class BI.HighlightBehavior
+ * @extends BI.Behavior
+ */
+BI.HighlightBehavior = BI.inherit(BI.Behavior, {
+    _defaultConfig: function() {
+        return BI.extend(BI.HighlightBehavior.superclass._defaultConfig.apply(this, arguments), {
+
+        });
+    },
+
+    _init : function() {
+        BI.HighlightBehavior.superclass._init.apply(this, arguments);
+
+    },
+
+    doBehavior: function(items){
+        var args = Array.prototype.slice.call(arguments, 1),
+            o = this.options;
+        BI.each(items, function(i, item){
+            if(item instanceof BI.Single) {
+                if (o.rule(item.getValue(), item)) {
+                    item.doHighLight.apply(item, args);
+                } else {
+                    item.unHighLight.apply(item, args);
+                }
+            } else {
+                item.doBehavior.apply(item, args);
+            }
+        })
+    }
+});/**
+ * guy
+ * 标红行为
+ * @class BI.RedMarkBehavior
+ * @extends BI.Behavior
+ */
+BI.RedMarkBehavior = BI.inherit(BI.Behavior, {
+    _defaultConfig: function() {
+        return BI.extend(BI.RedMarkBehavior.superclass._defaultConfig.apply(this, arguments), {
+
+        });
+    },
+
+    _init : function() {
+        BI.RedMarkBehavior.superclass._init.apply(this, arguments);
+
+    },
+
+    doBehavior: function(items){
+        var args  = Array.prototype.slice.call(arguments, 1),
+            o     = this.options;
+        BI.each(items, function(i, item){
+            if(item instanceof BI.Single) {
+                if (o.rule(item.getValue(), item)) {
+                    item.doRedMark.apply(item, args);
+                } else {
+                    item.unRedMark.apply(item, args);
+                }
+            } else {
+                item.doBehavior.apply(item, args);
+            }
+        })
+    }
+});/*
+ * 前端缓存
+ */
+window.localStorage || (window.localStorage = {
+    items: {},
+    setItem: function (k, v) {
+        BI.Cache.addCookie(k, v);
+    },
+    getItem: function (k) {
+        return BI.Cache.getCookie(k);
+    },
+    removeItem: function (k) {
+        BI.Cache.deleteCookie(k);
+    },
+    key: function () {
+
+    },
+    clear: function () {
+        this.items = {};
+    }
+});
+BI.Cache = {
+    _prefix: "bi",
+    setUsername: function (username) {
+        localStorage.setItem(BI.Cache._prefix + ".username", (username + "" || "").toUpperCase());
+    },
+    getUsername: function () {
+        return localStorage.getItem(BI.Cache._prefix + ".username") || "";
+    },
+    _getKeyPrefix: function () {
+        return BI.Cache.getUsername() + "." + BI.Cache._prefix + ".";
+    },
+    _generateKey: function (key) {
+        return BI.Cache._getKeyPrefix() + (key || "");
+    },
+    getItem: function (key) {
+        return localStorage.getItem(BI.Cache._generateKey(key));
+    },
+    setItem: function (key, value) {
+        localStorage.setItem(BI.Cache._generateKey(key), value);
+    },
+    removeItem: function (key) {
+        localStorage.removeItem(BI.Cache._generateKey(key));
+    },
+    clear: function () {
+        for (var i = localStorage.length; i >= 0; i--) {
+            var key = localStorage.key(i);
+            if (key) {
+                if (key.indexOf(BI.Cache._getKeyPrefix()) === 0) {
+                    localStorage.removeItem(key);
+                }
+            }
+        }
+    },
+    keys: function () {
+        var result = [];
+        for (var i = localStorage.length; i >= 0; i--) {
+            var key = localStorage.key(i);
+            if (key) {
+                var prefix = BI.Cache._getKeyPrefix();
+                if (key.indexOf(prefix) === 0) {
+                    result[result.length] = key.substring(prefix.length);
+                }
+            }
+        }
+        return result;
+    },
+
+    addCookie: function (name, value, path, expiresHours) {
+        var cookieString = name + "=" + escape(value);
+        // 判断是否设置过期时间
+        if (expiresHours && expiresHours > 0) {
+            var date = new Date();
+            date.setTime(date.getTime() + expiresHours * 3600 * 1000);
+            cookieString = cookieString + "; expires=" + date.toGMTString();
+        }
+        if (path) {
+            cookieString = cookieString + "; path=" + path;
+        }
+        document.cookie = cookieString;
+    },
+    getCookie: function (name) {
+        var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
+        if (arr = document.cookie.match(reg))
+            return unescape(arr[2]);
+        else
+            return null;
+    },
+    deleteCookie: function (name, path) {
+        var date = new Date();
+        date.setTime(date.getTime() - 10000);
+        var cookieString = name + "=v; expires=" + date.toGMTString();
+        if (path) {
+            cookieString = cookieString + "; path=" + path;
+        }
+        document.cookie = cookieString;
+    }
+};/**
+ * guy
+ * 控制器
+ * Controller层超类
+ * @class BI.Controller
+ * @extends FR.OB
+ * @abstract
+ */
+BI.Controller = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.Controller.superclass._defaultConfig.apply(this, arguments), {
+
+        })
+    },
+    _init : function() {
+        BI.Controller.superclass._init.apply(this, arguments);
+    },
+
+    destroy: function(){
+
+    }
+});
+BI.Controller.EVENT_CHANGE = "__EVENT_CHANGE__";/**
+ * 广播
+ *
+ * Created by GUY on 2015/12/23.
+ * @class
+ */
+BI.BroadcastController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BroadcastController.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    _init: function () {
+        BI.BroadcastController.superclass._init.apply(this, arguments);
+        this._broadcasts = {};
+    },
+
+    on: function (name, fn) {
+        if (!this._broadcasts[name]) {
+            this._broadcasts[name] = [];
+        }
+        this._broadcasts[name].push(fn);
+    },
+
+    send: function (name) {
+        var args = [].slice.call(arguments, 1);
+        BI.each(this._broadcasts[name], function (i, fn) {
+            fn.apply(null, args);
+        });
+    },
+
+    remove: function (name, fn) {
+        if (fn) {
+            BI.remove(this._broadcasts[name], fn);
+        } else {
+            delete this._broadcasts[name];
+        }
+        return this;
+    }
+});/**
+ * 气泡图控制器
+ * 控制气泡图的显示方向
+ *
+ * Created by GUY on 2015/8/21.
+ * @class
+ */
+BI.BubblesController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.BubblesController.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    _const: {
+        bubbleHeight: 35
+    },
+
+    _init: function () {
+        BI.BubblesController.superclass._init.apply(this, arguments);
+        this.bubblesManager = {};
+        this.storeBubbles = {};
+    },
+
+    _createBubble: function (direct, text, height) {
+        return BI.createWidget({
+            type: "bi.bubble",
+            text: text,
+            height: height || 35,
+            direction: direct
+        });
+    },
+
+    hide: function (name, callback) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this.get(name).element.hide(0, callback);
+        this.get(name).invisible();
+        return this;
+    },
+
+    _getOffsetLeft: function(name, context, offsetStyle){
+        var left = 0;
+        if ("center" === offsetStyle) {
+            left = context.element.offset().left + (context.element.bounds().width - this.get(name).element.bounds().width) / 2;
+            if (left < 0) {
+                left = 0;
+            }
+            return left;
+        }
+        if ("right" === offsetStyle) {
+            left = context.element.offset().left + context.element.bounds().width - this.get(name).element.bounds().width;
+            if (left < 0) {
+                left = 0;
+            }
+            return left;
+        }
+        return context.element.offset().left;
+    },
+
+    _getOffsetTop: function(name, context, offsetStyle){
+        var top = 0;
+        if ("center" === offsetStyle) {
+            top = context.element.offset().top + (context.element.bounds().height - this.get(name).element.bounds().height) / 2;
+            if (top < 0) {
+                top = 0;
+            }
+            return top;
+        } else if ("right" === offsetStyle) {
+            top = context.element.offset().top + context.element.bounds().height - this.get(name).element.bounds().height;
+            if (top < 0) {
+                top = 0;
+            }
+            return top;
+        }
+        return context.element.offset().top;
+    },
+
+    _getLeftPosition: function(name, context, offsetStyle){
+        var position = $.getLeftPosition(context, this.get(name));
+        position.top = this._getOffsetTop(name, context, offsetStyle);
+        return position;
+    },
+
+    _getBottomPosition: function(name, context, offsetStyle){
+        var position = $.getBottomPosition(context, this.get(name));
+        position.left = this._getOffsetLeft(name, context, offsetStyle);
+        return position;
+    },
+
+    _getTopPosition: function(name, context, offsetStyle){
+        var position = $.getTopPosition(context, this.get(name));
+        position.left = this._getOffsetLeft(name, context, offsetStyle);
+        return position;
+    },
+
+    _getRightPosition: function(name, context, offsetStyle){
+        var position = $.getRightPosition(context, this.get(name));
+        position.top = this._getOffsetTop(name, context, offsetStyle);
+        return position;
+    },
+
+    /**
+     *
+     * @param name
+     * @param text
+     * @param context
+     * @param offsetStyle center, left, right三种类型, 默认left
+     * @returns {BI.BubblesController}
+     */
+    show: function (name, text, context, opt) {
+        opt || (opt = {});
+        var container = opt.container || context;
+        var offsetStyle = opt.offsetStyle || {};
+        if (!this.storeBubbles[name]) {
+            this.storeBubbles[name] = {};
+        }
+        if (!this.storeBubbles[name]["top"]) {
+            this.storeBubbles[name]["top"] = this._createBubble("top", text);
+        }
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container,
+            items: [{
+                el: this.storeBubbles[name]["top"]
+            }]
+        })
+        this.set(name, this.storeBubbles[name]["top"])
+        var position = this._getTopPosition(name, context, offsetStyle);
+        this.get(name).element.css({left: position.left, top: position.top});
+        this.get(name).invisible();
+        if (!$.isTopSpaceEnough(context, this.get(name))) {
+            if (!this.storeBubbles[name]["left"]) {
+                this.storeBubbles[name]["left"] = this._createBubble("left", text, 30);
+            }
+            BI.createWidget({
+                type: "bi.absolute",
+                element: container,
+                items: [{
+                    el: this.storeBubbles[name]["left"]
+                }]
+            })
+            this.set(name, this.storeBubbles[name]["left"]);
+            var position = this._getLeftPosition(name, context, offsetStyle);
+            this.get(name).element.css({left: position.left, top: position.top});
+            this.get(name).invisible();
+            if (!$.isLeftSpaceEnough(context, this.get(name))) {
+                if (!this.storeBubbles[name]["right"]) {
+                    this.storeBubbles[name]["right"] = this._createBubble("right", text, 30);
+                }
+                BI.createWidget({
+                    type: "bi.absolute",
+                    element: container,
+                    items: [{
+                        el: this.storeBubbles[name]["right"]
+                    }]
+                })
+                this.set(name, this.storeBubbles[name]["right"])
+                var position = this._getRightPosition(name, context, offsetStyle);
+                this.get(name).element.css({left: position.left, top: position.top});
+                this.get(name).invisible();
+                if (!$.isRightSpaceEnough(context, this.get(name))) {
+                    if (!this.storeBubbles[name]["bottom"]) {
+                        this.storeBubbles[name]["bottom"] = this._createBubble("bottom", text);
+                    }
+                    BI.createWidget({
+                        type: "bi.absolute",
+                        element: container,
+                        items: [{
+                            el: this.storeBubbles[name]["bottom"]
+                        }]
+                    });
+                    this.set(name, this.storeBubbles[name]["bottom"]);
+                    var position = this._getBottomPosition(name, context, offsetStyle);
+                    this.get(name).element.css({left: position.left, top: position.top});
+                    this.get(name).invisible();
+                }
+            }
+        }
+        this.get(name).setText(text);
+        this.get(name).visible();
+        return this;
+    },
+
+    add: function (name, bubble) {
+        if (this.has(name)) {
+            return this;
+        }
+        this.set(name, bubble);
+        return this;
+    },
+
+    get: function (name) {
+        return this.bubblesManager[name];
+    },
+
+    set: function (name, bubble) {
+        this.bubblesManager[name] = bubble;
+    },
+
+    has: function (name) {
+        return this.bubblesManager[name] != null;
+    },
+
+    remove: function (name) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this.bubblesManager[name].destroy();
+        delete this.bubblesManager[name];
+        return this;
+    }
+});/**
+ * guy
+ * FloatBox弹出层控制器, z-index在100w层级
+ * @class BI.FloatBoxController
+ * @extends BI.Controller
+ */
+BI.FloatBoxController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FloatBoxController.superclass._defaultConfig.apply(this, arguments), {
+            modal: true, // 模态窗口
+            render: "body"
+        });
+    },
+
+    _init: function () {
+        BI.FloatBoxController.superclass._init.apply(this, arguments);
+        this.modal = this.options.modal;
+        this.floatManager = {};
+        this.floatLayer = {};
+        this.floatContainer = {};
+        this.zindex = BI.zIndex_floatbox;
+        this.zindexMap = {};
+    },
+
+    _check: function (name) {
+        return BI.isNotNull(this.floatManager[name]);
+    },
+
+    create: function (name, section, options) {
+        if (this._check(name)) {
+            return this;
+        }
+        var floatbox = BI.createWidget({
+            type: "bi.float_box"
+        }, options);
+        floatbox.populate(section);
+        this.add(name, floatbox, options);
+        return this;
+    },
+
+    add: function (name, floatbox, options) {
+        var self = this;
+        options || (options = {});
+        if (this._check(name)) {
+            return this;
+        }
+        this.floatContainer[name] = BI.createWidget({
+            type: "bi.absolute",
+            cls: "bi-list-view",
+            items: [{
+                el: (this.floatLayer[name] = BI.createWidget({
+                    type: 'bi.absolute',
+                    items: [floatbox]
+                })),
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.floatManager[name] = floatbox;
+        (function (key) {
+            floatbox.on(BI.FloatBox.EVENT_FLOAT_BOX_CLOSED, function () {
+                self.close(key);
+            })
+        })(name);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: options.container || this.options.render,
+            items: [{
+                el: this.floatContainer[name],
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        return this;
+    },
+
+    open: function (name) {
+        if (!this._check(name)) {
+            return this;
+        }
+        var container = this.floatContainer[name];
+        container.element.css("zIndex", this.zindex++);
+        this.modal && container.element.__hasZIndexMask__(this.zindexMap[name]) && container.element.__releaseZIndexMask__(this.zindexMap[name]);
+        this.zindexMap[name] = this.zindex;
+        this.modal && container.element.__buildZIndexMask__(this.zindex++);
+        this.get(name).setZindex(this.zindex++);
+        this.floatContainer[name].visible();
+        var floatbox = this.get(name);
+        floatbox.show();
+        var W = $(this.options.render).width(), H = $(this.options.render).height();
+        var w = floatbox.element.width(), h = floatbox.element.height();
+        var left = (W - w) / 2, top = (H - h) / 2;
+        if (left < 0) {
+            left = 0;
+        }
+        if (top < 0) {
+            top = 0;
+        }
+        floatbox.element.css({
+            left: left + "px",
+            top: top + "px"
+        });
+        return this;
+    },
+
+    close: function (name) {
+        if (!this._check(name)) {
+            return this;
+        }
+        this.floatContainer[name].invisible();
+        this.modal && this.floatContainer[name].element.__releaseZIndexMask__(this.zindexMap[name]);
+        return this;
+    },
+
+    get: function (name) {
+        return this.floatManager[name];
+    },
+
+    remove: function (name) {
+        if (!this._check(name)) {
+            return this;
+        }
+        this.floatContainer[name].destroy();
+        this.modal && this.floatContainer[name].element.__releaseZIndexMask__(this.zindexMap[name]);
+        delete this.floatManager[name];
+        delete this.floatLayer[name];
+        delete this.zindexMap[name];
+        delete this.floatContainer[name];
+        return this;
+    }
+});/**
+ * 弹出层面板控制器, z-index在10w层级
+ *
+ * Created by GUY on 2015/6/24.
+ * @class
+ */
+BI.LayerController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LayerController.superclass._defaultConfig.apply(this, arguments), {
+            render: "body"
+        });
+    },
+
+    _init: function () {
+        BI.LayerController.superclass._init.apply(this, arguments);
+        this.layerManager = {};
+        this.layouts = {};
+        this.zindex = BI.zIndex_layer;
+        BI.Resizers.add("layerController" + BI.uniqueId(), BI.bind(this._resize, this));
+    },
+
+    _resize: function () {
+        BI.each(this.layouts, function (i, layer) {
+            if (layer.element.is(":visible")) {
+                layer.element.trigger("__resize__");
+            }
+        })
+    },
+
+    make: function (name, container, op) {
+        if (this.has(name)) {
+            return this.get(name);
+        }
+        op || (op = {});
+        var widget = BI.createWidget((op.render || {}), {
+            type: "bi.layout"
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container || this.options.render,
+            items: [BI.extend({
+                el: widget
+            }, {
+                top: 0,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }, op.offset)]
+        });
+        this.add(name, widget, widget);
+        return widget;
+    },
+
+    create: function (name, from, op) {
+        if (this.has(name)) {
+            return this.get(name);
+        }
+        op || (op = {});
+        var offset = op.offset || {};
+        var w = from;
+        if (BI.isWidget(from)) {
+            w = from.element;
+        }
+        if (BI.isNotEmptyString(w)) {
+            w = $(w);
+        }
+        if (this.has(name)) {
+            return this.get(name);
+        }
+        var widget = BI.createWidget((op.render || {}), {
+            type: "bi.layout"
+        });
+        var layout = BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: widget,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: op.container || this.options.render,
+            items: [{
+                el: layout,
+                left: offset.left || 0,
+                right: offset.right || 0,
+                top: offset.top || 0,
+                bottom: offset.bottom || 0
+            }]
+        });
+        if (w) {
+            layout.element.addClass("bi-list-view");
+            layout.element.css({
+                left: w.offset().left + (offset.left || 0),
+                top: w.offset().top + (offset.top || 0),
+                width: offset.width || (w.outerWidth() - (offset.right || 0)) || "",
+                height: offset.height || (w.outerHeight() - (offset.bottom || 0)) || ""
+            });
+            layout.element.on("__resize__", function () {
+                w.is(":visible") &&
+                layout.element.css({
+                    left: w.offset().left + (offset.left || 0),
+                    top: w.offset().top + (offset.top || 0),
+                    width: offset.width || (w.outerWidth() - (offset.right || 0)) || "",
+                    height: offset.height || (w.outerHeight() - (offset.bottom || 0)) || ""
+                });
+            });
+        }
+        this.add(name, widget, layout);
+        return widget;
+    },
+
+    hide: function (name, callback) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this._getLayout(name).invisible();
+        this._getLayout(name).element.hide(0, callback);
+        return this;
+    },
+
+    show: function (name, callback) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this._getLayout(name).visible();
+        this._getLayout(name).element.css("z-index", this.zindex++).show(0, callback).trigger("__resize__");
+        return this;
+    },
+
+    isVisible: function (name) {
+        return this.has(name) && this._getLayout(name).isVisible();
+    },
+
+    add: function (name, layer, layout) {
+        if (this.has(name)) {
+            throw new Error("该弹出面板已经存在了,不能添加该key值");
+        }
+        layout.setVisible(false);
+        this.layerManager[name] = layer;
+        this.layouts[name] = layout;
+        layout.element.css("z-index", this.zindex++);
+        return this;
+    },
+
+    _getLayout: function (name) {
+        return this.layouts[name];
+    },
+
+    get: function (name) {
+        return this.layerManager[name];
+    },
+
+    has: function (name) {
+        return this.layerManager[name] != null;
+    },
+
+    remove: function (name) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this.layerManager[name].destroy();
+        this.layouts[name].destroy();
+        delete this.layerManager[name];
+        delete this.layouts[name];
+        return this;
+    }
+});/**
+ * 遮罩面板, z-index在1亿层级
+ *
+ * Created by GUY on 2015/6/24.
+ * @class
+ */
+BI.MaskersController = BI.inherit(BI.LayerController, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MaskersController.superclass._defaultConfig.apply(this, arguments), {
+            render: "body"
+        });
+    },
+
+    _init: function () {
+        BI.MaskersController.superclass._init.apply(this, arguments);
+        this.zindex = BI.zIndex_masker;
+    }
+});/**
+ * window.resize 控制器
+ *
+ * Created by GUY on 2015/6/24.
+ * @class
+ */
+BI.ResizeController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ResizeController.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    _init: function () {
+        BI.ResizeController.superclass._init.apply(this, arguments);
+        var self = this;
+        this.resizerManger = {};
+        var fn = BI.debounce(function (ev) {
+            //if (BI.isWindow(ev.target)) {
+            self._resize(ev);
+            //}
+        }, 30);
+        $(window).resize(fn);
+    },
+
+    _resize: function (ev) {
+        BI.each(this.resizerManger, function (key, resizer) {
+            if (resizer instanceof $) {
+                if (resizer.is(":visible")) {
+                    resizer.trigger("__resize__");
+                }
+                return;
+            }
+            if (resizer instanceof BI.Layout) {
+                resizer.resize();
+                return;
+            }
+            if (BI.isFunction(resizer)) {
+                resizer(ev);
+                return;
+            }
+        })
+    },
+
+    add: function (name, resizer) {
+        if (this.has(name)) {
+            return this;
+        }
+        this.resizerManger[name] = resizer;
+        return this;
+    },
+
+    get: function (name) {
+        return this.resizerManger[name];
+    },
+
+    has: function (name) {
+        return this.resizerManger[name] != null;
+    },
+
+    remove: function (name) {
+        if (!this.has(name)) {
+            return this;
+        }
+        delete this.resizerManger[name];
+        return this;
+    }
+});/**
+ * tooltip控制器
+ * 控制tooltip的显示,  且页面中只有一个tooltip显示
+ *
+ * Created by GUY on 2015/9/8.
+ * @class BI.TooltipsController
+ * @extends BI.Controller
+ */
+BI.TooltipsController = BI.inherit(BI.Controller, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TooltipsController.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    _const: {
+        height: 20
+    },
+
+    _init: function () {
+        BI.TooltipsController.superclass._init.apply(this, arguments);
+        this.tooltipsManager = {};
+        this.showingTips = {};//存储正在显示的tooltip
+    },
+
+    _createTooltip: function (text, level) {
+        return BI.createWidget({
+            type: "bi.tooltip",
+            text: text,
+            level: level,
+            height: this._const.height
+        });
+    },
+
+    hide: function (name, callback) {
+        if (!this.has(name)) {
+            return this;
+        }
+        delete this.showingTips[name];
+        this.get(name).element.hide(0, callback);
+        this.get(name).invisible();
+        return this;
+    },
+
+    create: function (name, text, level, context) {
+        if (!this.has(name)) {
+            var tooltip = this._createTooltip(text, level);
+            this.add(name, tooltip);
+            BI.createWidget({
+                type: "bi.absolute",
+                element: context || "body",
+                items: [{
+                    el: tooltip
+                }]
+            });
+            tooltip.invisible();
+        }
+        return this.get(name);
+    },
+
+    //opt: {container: '', belowMouse: false}
+    show: function (e, name, text, level, context, opt) {
+        opt || (opt = {});
+        var self = this;
+        BI.each(this.showingTips, function (i, tip) {
+            self.hide(i);
+        });
+        this.showingTips = {};
+        if (!this.has(name)) {
+            this.create(name, text, level, opt.container || context);
+        }
+
+        var offset = context.element.offset();
+        var bounds = context.element.bounds();
+
+        var top = offset.top + bounds.height + 5;
+        var tooltip = this.get(name);
+        tooltip.setText(text);
+        tooltip.element.css({
+            left: "0px",
+            top: "0px"
+        });
+        tooltip.visible();
+        tooltip.element.height(tooltip.element[0].scrollHeight);
+        this.showingTips[name] = true;
+        var x = e.pageX || e.clientX, y = (e.pageY || e.clientY) + 15;
+        if (x + tooltip.element.outerWidth() > $("body").outerWidth()) {
+            x -= tooltip.element.outerWidth();
+        }
+        if (y + tooltip.element.outerHeight() > $("body").outerHeight()) {
+            y -= tooltip.element.outerHeight() + 15;
+            top = offset.top - tooltip.element.outerHeight() - 5;
+            !opt.belowMouse && (y = Math.min(y, top));
+        } else {
+            !opt.belowMouse && (y = Math.max(y, top));
+        }
+        tooltip.element.css({
+            left: x < 0 ? 0 : x + "px",
+            top: y < 0 ? 0 : y + "px"
+        });
+        tooltip.element.hover(function () {
+            self.remove(name);
+            context.element.trigger("mouseleave.title" + context.getName());
+        });
+        return this;
+    },
+
+    add: function (name, bubble) {
+        if (this.has(name)) {
+            return this;
+        }
+        this.set(name, bubble);
+        return this;
+    },
+
+    get: function (name) {
+        return this.tooltipsManager[name];
+    },
+
+    set: function (name, bubble) {
+        this.tooltipsManager[name] = bubble;
+    },
+
+    has: function (name) {
+        return this.tooltipsManager[name] != null;
+    },
+
+    remove: function (name) {
+        if (!this.has(name)) {
+            return this;
+        }
+        this.tooltipsManager[name].destroy();
+        delete this.tooltipsManager[name];
+        return this;
+    }
+});/**
+ *
+ * @class BI.FloatBoxRouter
+ * @extends BI.WRouter
+ */
+BI.FloatBoxRouter = BI.inherit(BI.WRouter, {
+    routes: {},
+
+    _init: function () {
+        this.store = {};
+        this.views = {};
+    },
+
+    createView: function (url, modelData, viewData, context) {
+        return BI.Factory.createView(url, this.get(url), modelData || {}, viewData || {}, context)
+    },
+
+    open: function (url, modelData, viewData, context, options) {
+        var self = this, isValid = BI.isKey(modelData);
+        options || (options = {});
+        url = context.rootURL + "/" + url;
+        var data = void 0;
+        if (isValid) {
+            modelData = modelData + "";//避免modelData是数字
+            var keys = modelData.split('.');
+            BI.each(keys, function (i, k) {
+                if (i === 0) {
+                    data = context.model.get(k) || {};
+                } else {
+                    data = data[k] || {};
+                }
+            });
+            data.id = options.id || keys[keys.length - 1];
+        } else {
+            data = modelData;
+        }
+        BI.extend(data, options.data);
+        if (!this.controller) {
+            this.controller = new BI.FloatBoxController();
+        }
+        if (!this.store[url]) {
+            this.store[url] = BI.createWidget({
+                type: "bi.float_box"
+            }, options);
+            var view = this.createView(url, data, viewData, context);
+            isValid && context.model.addChild(modelData, view.model);
+            view.listenTo(view.model, "destroy", function () {
+                self.remove(url);
+            });
+            this.store[url].populate(view);
+            this.views[url] = view;
+            this.controller.add(url, this.store[url]);
+            context && context.on("end:" + view.cid, function () {
+                BI.nextTick(function () {
+                    self.close(url);
+//                    view.end();
+                    var t = void 0, isNew = false, keys;
+                    if (isValid) {
+                        keys = modelData.split('.');
+                        BI.each(keys, function (i, k) {
+                            if (i === 0) {
+                                t = context.model.get(k) || (isNew = true);
+                            } else {
+                                t = t[k] || (isNew = true);
+                            }
+                        })
+                    }
+                    isNew && context.model.removeChild(modelData);
+                    !isNew && (context.listenEnd.apply(context, isValid ? keys : [modelData]) !== false) && context.populate();
+                }, 30)
+            }).on("change:" + view.cid, _.bind(context.notifyParent, context))
+        }
+        this.controller.open(url);
+        this.views[url].populate(data, options.force || true);
+        return this;
+    },
+
+    close: function (url) {
+        if (this.controller) {
+            this.controller.close(url);
+        }
+        return this;
+    },
+
+    remove: function (url, context) {
+        url = context.rootURL + "/" + url;
+        if(this.controller){
+            this.controller.remove(url);
+            delete this.store[url];
+            this.views[url] && this.views[url].destroy();
+            delete this.views[url];
+        }
+        return this;
+    }
+});/**
+ * 统一绑定事件
+ * @type {*|void|Object}
+ */
+BI.EventList = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.EventList.superclass._defaultConfig.apply(this, arguments), {
+            event: "click",
+            callback: BI.emptyFn,
+            handle: "",
+            items:[]
+        });
+    },
+
+    _init : function() {
+        BI.EventList.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getHandle: function(item){
+        var handle = this.options.handle ? _.result(item, this.options.handle) : item;
+        return handle.element || handle;
+    },
+
+    populate: function(items){
+        var self    = this,
+            event   = this.options.event,
+            callback = this.options.callback;
+        BI.nextTick(function(){
+            BI.each(items, function(i, item){
+                var fn  = callback(item);
+                BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true));
+                self._getHandle(item)[event](fn);
+            })
+        })
+
+    }
+});/**
+ * 统一监听jquery事件
+ * @type {*|void|Object}
+ */
+BI.ListenerList = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.ListenerList.superclass._defaultConfig.apply(this, arguments), {
+            event: "click",
+            callback: BI.emptyFn,
+            items:[]
+        });
+    },
+
+    _init : function() {
+        BI.ListenerList.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getHandle: function(item){
+        var handle = this.options.handle ? _.result(item, this.options.handle) : item;
+        return handle.element || handle;
+    },
+
+    populate: function(items){
+        var self     = this,
+            event    = this.options.event,
+            callback = this.options.callback;
+        BI.nextTick(function(){
+            BI.each(items, function(i, item){
+                var fn  = callback(item);
+                BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true));
+                self._getHandle(item).on(event, fn);
+            })
+        })
+    }
+});/**
+ * Created by GUY on 2015/6/25.
+ */
+/**
+ * 统一监听jquery事件
+ * @type {*|void|Object}
+ */
+BI.OffList = BI.inherit(BI.OB, {
+    _defaultConfig: function() {
+        return BI.extend(BI.OffList.superclass._defaultConfig.apply(this, arguments), {
+            event: "click",
+            items:[]
+        });
+    },
+
+    _init : function() {
+        BI.OffList.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getHandle: function(item){
+        var handle = this.options.handle ? _.result(item, this.options.handle) : item;
+        return handle.element || handle;
+    },
+
+    populate: function(items){
+        var self   = this,
+            event  = this.options.event;
+        BI.each(items, function(i, item){
+            self._getHandle(item).off(event);
+        })
+    }
+});/**
+ * 事件集合
+ * @class BI.Events
+ */
+_.extend(BI, {
+    Events: {
+
+        /**
+         * @static
+         * @property keydown事件
+         */
+        KEYDOWN: "_KEYDOWN",
+
+        /**
+         * @static
+         * @property 回撤事件
+         */
+        BACKSPACE: "_BACKSPACE",
+
+        /**
+         * @static
+         * @property 空格事件
+         */
+        SPACE: "_SPACE",
+
+        /**
+         * @static
+         * @property 回车事件
+         */
+        ENTER: "_ENTER",
+
+        /**
+         * @static
+         * @property 确定事件
+         */
+        CONFIRM: '_CONFIRM',
+
+        /**
+         * @static
+         * @property 错误事件
+         */
+        ERROR: '_ERROR',
+
+        /**
+         * @static
+         * @property 暂停事件
+         */
+        PAUSE: '_PAUSE',
+
+        /**
+         * @static
+         * @property destroy事件
+         */
+        DESTROY: '_DESTROY',
+
+        /**
+         * @static
+         * @property 清除选择
+         */
+        CLEAR: '_CLEAR',
+
+        /**
+         * @static
+         * @property 添加数据
+         */
+        ADD: '_ADD',
+
+        /**
+         * @static
+         * @property 正在编辑状态事件
+         */
+        EDITING: '_EDITING',
+
+        /**
+         * @static
+         * @property 空状态事件
+         */
+        EMPTY: '_EMPTY',
+
+        /**
+         * @static
+         * @property 显示隐藏事件
+         */
+        VIEW: '_VIEW',
+
+        /**
+         * @static
+         * @property 窗体改变大小
+         */
+        RESIZE: "_RESIZE",
+
+        /**
+         * @static
+         * @property 编辑前事件
+         */
+        BEFOREEDIT: '_BEFOREEDIT',
+
+        /**
+         * @static
+         * @property 编辑后事件
+         */
+        AFTEREDIT: '_AFTEREDIT',
+
+        /**
+         * @static
+         * @property 开始编辑事件
+         */
+        STARTEDIT: '_STARTEDIT',
+
+        /**
+         * @static
+         * @property 停止编辑事件
+         */
+        STOPEDIT: '_STOPEDIT',
+
+        /**
+         * @static
+         * @property 值改变事件
+         */
+        CHANGE: '_CHANGE',
+
+        /**
+         * @static
+         * @property 下拉弹出菜单事件
+         */
+        EXPAND: '_EXPAND',
+
+        /**
+         * @static
+         * @property 关闭下拉菜单事件
+         */
+        COLLAPSE: '_COLLAPSE',
+
+        /**
+         * @static
+         * @property 回调事件
+         */
+        CALLBACK: '_CALLBACK',
+
+        /**
+         * @static
+         * @property 点击事件
+         */
+        CLICK: '_CLICK',
+
+        /**
+         * @static
+         * @property 状态改变事件,一般是用在复选按钮和单选按钮
+         */
+        STATECHANGE: '_STATECHANGE',
+
+        /**
+         * @static
+         * @property 状态改变前事件
+         */
+        BEFORESTATECHANGE: '_BEFORESTATECHANGE',
+
+
+        /**
+         * @static
+         * @property 初始化事件
+         */
+        INIT: '_INIT',
+
+        /**
+         * @static
+         * @property 初始化后事件
+         */
+        AFTERINIT: '_AFTERINIT',
+
+        /**
+         * @static
+         * @property 滚动条滚动事件
+         */
+        SCROLL: '_SCROLL',
+
+
+        /**
+         * @static
+         * @property 开始加载事件
+         */
+        STARTLOAD: '_STARTLOAD',
+
+        /**
+         * @static
+         * @property 加载后事件
+         */
+        AFTERLOAD: '_AFTERLOAD',
+
+
+        /**
+         * @static
+         * @property 提交前事件
+         */
+        BS: 'beforesubmit',
+
+        /**
+         * @static
+         * @property 提交后事件
+         */
+        AS: 'aftersubmit',
+
+        /**
+         * @static
+         * @property 提交完成事件
+         */
+        SC: 'submitcomplete',
+
+        /**
+         * @static
+         * @property 提交失败事件
+         */
+        SF: 'submitfailure',
+
+        /**
+         * @static
+         * @property 提交成功事件
+         */
+        SS: 'submitsuccess',
+
+        /**
+         * @static
+         * @property 校验提交前事件
+         */
+        BVW: 'beforeverifywrite',
+
+        /**
+         * @static
+         * @property 校验提交后事件
+         */
+        AVW: 'afterverifywrite',
+
+        /**
+         * @static
+         * @property 校验后事件
+         */
+        AV: 'afterverify',
+
+        /**
+         * @static
+         * @property 填报前事件
+         */
+        BW: 'beforewrite',
+
+        /**
+         * @static
+         * @property 填报后事件
+         */
+        AW: 'afterwrite',
+
+        /**
+         * @static
+         * @property 填报成功事件
+         */
+        WS: 'writesuccess',
+
+        /**
+         * @static
+         * @property 填报失败事件
+         */
+        WF: 'writefailure',
+
+        /**
+         * @static
+         * @property 添加行前事件
+         */
+        BA: 'beforeappend',
+
+        /**
+         * @static
+         * @property 添加行后事件
+         */
+        AA: 'afterappend',
+
+        /**
+         * @static
+         * @property 删除行前事件
+         */
+        BD: 'beforedelete',
+
+        /**
+         * @static
+         * @property 删除行后事件
+         */
+        AD: 'beforedelete',
+
+        /**
+         * @static
+         * @property 未提交离开事件
+         */
+        UC: 'unloadcheck',
+
+
+        /**
+         * @static
+         * @property PDF导出前事件
+         */
+        BTOPDF: 'beforetopdf',
+
+        /**
+         * @static
+         * @property PDF导出后事件
+         */
+        ATOPDF: 'aftertopdf',
+
+        /**
+         * @static
+         * @property Excel导出前事件
+         */
+        BTOEXCEL: 'beforetoexcel',
+
+        /**
+         * @static
+         * @property Excel导出后事件
+         */
+        ATOEXCEL: 'aftertoexcel',
+
+        /**
+         * @static
+         * @property Word导出前事件
+         */
+        BTOWORD: 'beforetoword',
+
+        /**
+         * @static
+         * @property Word导出后事件
+         */
+        ATOWORD: 'aftertoword',
+
+        /**
+         * @static
+         * @property 图片导出前事件
+         */
+        BTOIMAGE: 'beforetoimage',
+
+        /**
+         * @static
+         * @property 图片导出后事件
+         */
+        ATOIMAGE: 'aftertoimage',
+
+        /**
+         * @static
+         * @property HTML导出前事件
+         */
+        BTOHTML: 'beforetohtml',
+
+        /**
+         * @static
+         * @property HTML导出后事件
+         */
+        ATOHTML: 'aftertohtml',
+
+        /**
+         * @static
+         * @property Excel导入前事件
+         */
+        BIMEXCEL: 'beforeimportexcel',
+
+        /**
+         * @static
+         * @property Excel导出后事件
+         */
+        AIMEXCEL: 'afterimportexcel',
+
+        /**
+         * @static
+         * @property PDF打印前事件
+         */
+        BPDFPRINT: 'beforepdfprint',
+
+        /**
+         * @static
+         * @property PDF打印后事件
+         */
+        APDFPRINT: 'afterpdfprint',
+
+        /**
+         * @static
+         * @property Flash打印前事件
+         */
+        BFLASHPRINT: 'beforeflashprint',
+
+        /**
+         * @static
+         * @property Flash打印后事件
+         */
+        AFLASHPRINT: 'afterflashprint',
+
+        /**
+         * @static
+         * @property Applet打印前事件
+         */
+        BAPPLETPRINT: 'beforeappletprint',
+
+        /**
+         * @static
+         * @property Applet打印后事件
+         */
+        AAPPLETPRINT: 'afterappletprint',
+
+        /**
+         * @static
+         * @property 服务器打印前事件
+         */
+        BSEVERPRINT: 'beforeserverprint',
+
+        /**
+         * @static
+         * @property 服务器打印后事件
+         */
+        ASERVERPRINT: 'afterserverprint',
+
+        /**
+         * @static
+         * @property 邮件发送前事件
+         */
+        BEMAIL: 'beforeemail',
+
+        /**
+         * @static
+         * @property 邮件发送后事件
+         */
+        AEMAIL: 'afteremail'
+    }
+});/**
+ * guy
+ * 最基础的dom操作
+ */
+BI.extend(jQuery.fn, {
+
+    destroy: function () {
+        this.remove();
+        if (BI.isIE() === true) {
+            this[0].outerHTML = '';
+        }
+    },
+    /**
+     * 高亮显示
+     * @param text 必需
+     * @param keyword
+     * @param py 必需
+     * @returns {*}
+     * @private
+     */
+    __textKeywordMarked__: function (text, keyword, py) {
+        if (!BI.isKey(keyword)) {
+            return this.text(text);
+        }
+        keyword = keyword + "";
+        keyword = BI.toUpperCase(keyword);
+        var textLeft = (text || "") + "";
+        py = (py || BI.makeFirstPY(text)) + "";
+        if (py != null) {
+            py = BI.toUpperCase(py);
+        }
+        this.empty();
+        while (true) {
+            var tidx = BI.toUpperCase(textLeft).indexOf(keyword);
+            var pidx = null;
+            if (py != null) {
+                pidx = py.indexOf(keyword);
+                if (pidx >= 0) {
+                    pidx = pidx % text.length;
+                }
+            }
+
+            if (tidx >= 0) {
+                this.append(textLeft.substr(0, tidx));
+                this.append($("<span>").addClass("bi-keyword-red-mark")
+                    .text(textLeft.substr(tidx, keyword.length)));
+
+                textLeft = textLeft.substr(tidx + keyword.length);
+                if (py != null) {
+                    py = py.substr(tidx + keyword.length);
+                }
+            } else if (pidx != null && pidx >= 0 && Math.floor(pidx / text.length) === Math.floor((pidx + keyword.length - 1) / text.length)) {
+                this.append(textLeft.substr(0, pidx));
+                this.append($("<span>").addClass("bi-keyword-red-mark")
+                    .text(textLeft.substr(pidx, keyword.length)));
+                if (py != null) {
+                    py = py.substr(pidx + keyword.length);
+                }
+                textLeft = textLeft.substr(pidx + keyword.length);
+            } else {
+                this.append(textLeft);
+                break;
+            }
+        }
+
+        return this;
+    },
+
+    getDomHeight: function (parent) {
+        var clone = $(this).clone();
+        clone.appendTo($(parent || "body"));
+        var height = clone.height();
+        clone.remove();
+        return height;
+    },
+
+    //是否有竖直滚动条
+    hasVerticalScroll: function () {
+        return this.height() > 0 && this[0].clientWidth < this[0].offsetWidth;
+    },
+
+    //是否有水平滚动条
+    hasHorizonScroll: function () {
+        return this.width() > 0 && this[0].clientHeight < this[0].offsetHeight;
+    },
+
+    //获取计算后的样式
+    getStyle: function (name) {
+        var node = this[0];
+        var computedStyle = void 0;
+
+        // W3C Standard
+        if (window.getComputedStyle) {
+            // In certain cases such as within an iframe in FF3, this returns null.
+            computedStyle = window.getComputedStyle(node, null);
+            if (computedStyle) {
+                return computedStyle.getPropertyValue(BI.hyphenate(name));
+            }
+        }
+        // Safari
+        if (document.defaultView && document.defaultView.getComputedStyle) {
+            computedStyle = document.defaultView.getComputedStyle(node, null);
+            // A Safari bug causes this to return null for `display: none` elements.
+            if (computedStyle) {
+                return computedStyle.getPropertyValue(BI.hyphenate(name));
+            }
+            if (name === 'display') {
+                return 'none';
+            }
+        }
+        // Internet Explorer
+        if (node.currentStyle) {
+            if (name === 'float') {
+                return node.currentStyle.cssFloat || node.currentStyle.styleFloat;
+            }
+            return node.currentStyle[BI.camelize(name)];
+        }
+        return node.style && node.style[BI.camelize(name)];
+    },
+
+    __isMouseInBounds__: function (e) {
+        var offset2Body = this.offset();
+        return !(e.pageX < offset2Body.left || e.pageX > offset2Body.left + this.outerWidth()
+        || e.pageY < offset2Body.top || e.pageY > offset2Body.top + this.outerHeight())
+    },
+
+    __hasZIndexMask__: function (zindex) {
+        return zindex && this.zIndexMask[zindex] != null;
+    },
+
+    __buildZIndexMask__: function (zindex, domArray) {
+        this.zIndexMask = this.zIndexMask || {};//存储z-index的mask
+        this.indexMask = this.indexMask || [];//存储mask
+        var mask = BI.createWidget({
+            type: "bi.center_adapt",
+            cls: "bi-z-index-mask",
+            items: domArray
+        });
+
+        mask.element.css({"z-index": zindex});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: mask,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+        this.indexMask.push(mask);
+        zindex && (this.zIndexMask[zindex] = mask);
+        return mask.element;
+    },
+
+    __releaseZIndexMask__: function (zindex) {
+        if (zindex && this.zIndexMask[zindex]) {
+            this.indexMask.remove(this.zIndexMask[zindex]);
+            this.zIndexMask[zindex].destroy();
+            return;
+        }
+        this.indexMask = this.indexMask || [];
+        var indexMask = this.indexMask.pop();
+        indexMask && indexMask.destroy();
+    }
+});
+
+BI.extend(jQuery, {
+
+    getLeftPosition: function (combo, popup, extraWidth) {
+        return {
+            left: combo.element.offset().left - popup.element.outerWidth() - (extraWidth || 0)
+        };
+    },
+
+    getRightPosition: function (combo, popup, extraWidth) {
+        var el = combo.element;
+        return {
+            left: el.offset().left + el.outerWidth() + (extraWidth || 0)
+        }
+    },
+
+    getTopPosition: function (combo, popup, extraHeight) {
+        return {
+            top: combo.element.offset().top - popup.element.outerHeight() - (extraHeight || 0)
+        };
+    },
+
+    getBottomPosition: function (combo, popup, extraHeight) {
+        var el = combo.element;
+        return {
+            top: el.offset().top + el.outerHeight() + (extraHeight || 0)
+        };
+    },
+
+    isLeftSpaceEnough: function (combo, popup, extraWidth) {
+        return $.getLeftPosition(combo, popup, extraWidth).left >= 0;
+    },
+
+    isRightSpaceEnough: function (combo, popup, extraWidth) {
+        var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        return $.getRightPosition(combo, popup, extraWidth).left + viewBounds.width <= windowBounds.width;
+    },
+
+    isTopSpaceEnough: function (combo, popup, extraHeight) {
+        return $.getTopPosition(combo, popup, extraHeight).top >= 0;
+    },
+
+    isBottomSpaceEnough: function (combo, popup, extraHeight) {
+        var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        return $.getBottomPosition(combo, popup, extraHeight).top + viewBounds.height <= windowBounds.height;
+    },
+
+    isRightSpaceLarger: function (combo) {
+        var windowBounds = $("body").bounds();
+        return windowBounds.width - combo.element.offset().left - combo.element.bounds().width >= combo.element.offset().left;
+    },
+
+    isBottomSpaceLarger: function (combo) {
+        var windowBounds = $("body").bounds();
+        return windowBounds.height - combo.element.offset().top - combo.element.bounds().height >= combo.element.offset().top;
+    },
+
+    getLeftAlignPosition: function (combo, popup, extraWidth) {
+        var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        var left = combo.element.offset().left + extraWidth;
+        if (left + viewBounds.width > windowBounds.width) {
+            left = windowBounds.width - viewBounds.width;
+        }
+        if (left < 0) {
+            left = 0;
+        }
+        return {
+            left: left
+        }
+    },
+
+    getLeftAdaptPosition: function (combo, popup, extraWidth) {
+        if ($.isLeftSpaceEnough(combo, popup, extraWidth)) {
+            return $.getLeftPosition(combo, popup, extraWidth);
+        }
+        return {
+            left: 0
+        }
+    },
+
+    getRightAlignPosition: function (combo, popup, extraWidth) {
+        var comboBounds = combo.element.bounds(), viewBounds = popup.element.bounds();
+        var left = combo.element.offset().left + comboBounds.width - viewBounds.width - extraWidth;
+        if (left < 0) {
+            left = 0;
+        }
+        return {
+            left: left
+        }
+    },
+
+    getRightAdaptPosition: function (combo, popup, extraWidth) {
+        if ($.isRightSpaceEnough(combo, popup, extraWidth)) {
+            return $.getRightPosition(combo, popup, extraWidth);
+        }
+        return {
+            left: $("body").bounds().width - popup.element.bounds().width
+        }
+    },
+
+    getTopAlignPosition: function (combo, popup, extraHeight, needAdaptHeight) {
+        var comboOffset = combo.element.offset();
+        var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        var top, adaptHeight;
+        if ($.isBottomSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
+            top = comboOffset.top + extraHeight;
+        } else if (needAdaptHeight) {
+            top = comboOffset.top + extraHeight;
+            adaptHeight = windowBounds.height - top;
+        } else {
+            top = windowBounds.height - popupBounds.height;
+            if (top < extraHeight) {
+                adaptHeight = windowBounds.height - extraHeight;
+            }
+        }
+        if (top < extraHeight) {
+            top = extraHeight;
+        }
+        return adaptHeight ? {
+            top: top,
+            adaptHeight: adaptHeight
+        } : {
+            top: top
+        }
+    },
+
+    getTopAdaptPosition: function (combo, popup, extraHeight, needAdaptHeight) {
+        var popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        if ($.isTopSpaceEnough(combo, popup, extraHeight)) {
+            return $.getTopPosition(combo, popup, extraHeight);
+        }
+        if (needAdaptHeight) {
+            return {
+                top: 0,
+                adaptHeight: combo.element.offset().top - extraHeight
+            }
+        }
+        if (popupBounds.height + extraHeight > windowBounds.height) {
+            return {
+                top: 0,
+                adaptHeight: windowBounds.height - extraHeight
+            }
+        }
+        return {
+            top: 0
+        }
+    },
+
+    getBottomAlignPosition: function (combo, popup, extraHeight, needAdaptHeight) {
+        var comboOffset = combo.element.offset();
+        var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        var top, adaptHeight;
+        if ($.isTopSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
+            top = comboOffset.top + comboBounds.height - popupBounds.height - extraHeight;
+        } else if (needAdaptHeight) {
+            top = 0;
+            adaptHeight = comboOffset.top + comboBounds.height - extraHeight;
+        } else {
+            top = 0;
+            if (popupBounds.height + extraHeight > windowBounds.height) {
+                adaptHeight = windowBounds.height - extraHeight;
+            }
+        }
+        if (top < 0) {
+            top = 0;
+        }
+        return adaptHeight ? {
+            top: top,
+            adaptHeight: adaptHeight
+        } : {
+            top: top
+        }
+    },
+
+    getBottomAdaptPosition: function (combo, popup, extraHeight, needAdaptHeight) {
+        var comboOffset = combo.element.offset();
+        var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        if ($.isBottomSpaceEnough(combo, popup, extraHeight)) {
+            return $.getBottomPosition(combo, popup, extraHeight);
+        }
+        if (needAdaptHeight) {
+            return {
+                top: comboOffset.top + comboBounds.height + extraHeight,
+                adaptHeight: windowBounds.height - comboOffset.top - comboBounds.height - extraHeight
+            }
+        }
+        if (popupBounds.height + extraHeight > windowBounds.height) {
+            return {
+                top: extraHeight,
+                adaptHeight: windowBounds.height - extraHeight
+            }
+        }
+        return {
+            top: windowBounds.height - popupBounds.height - extraHeight
+        }
+    },
+
+    getCenterAdaptPosition: function (combo, popup) {
+        var comboOffset = combo.element.offset();
+        var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        var left;
+        if (comboOffset.left + comboBounds.width / 2 + popupBounds.width / 2 > windowBounds.width) {
+            left = windowBounds.width - popupBounds.width;
+        } else {
+            left = comboOffset.left + comboBounds.width / 2 - popupBounds.width / 2;
+        }
+        if (left < 0) {
+            left = 0;
+        }
+        return {
+            left: left
+        }
+    },
+
+    getMiddleAdaptPosition: function (combo, popup) {
+        var comboOffset = combo.element.offset();
+        var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds();
+        var top;
+        if (comboOffset.top + comboBounds.height / 2 + popupBounds.height / 2 > windowBounds.height) {
+            top = windowBounds.height - popupBounds.height;
+        } else {
+            top = comboOffset.top + comboBounds.height / 2 - popupBounds.height / 2;
+        }
+        if (top < 0) {
+            top = 0;
+        }
+        return {
+            top: top
+        }
+    },
+
+    getComboPositionByDirections: function (combo, popup, extraWidth, extraHeight, needAdaptHeight, directions) {
+        extraWidth || (extraWidth = 0);
+        extraHeight || (extraHeight = 0);
+        var i, direct;
+        var leftRight = [], topBottom = [];
+        var isNeedAdaptHeight = false, tbFirst = false, lrFirst = false;
+        var left, top, pos;
+        for (i = 0; i < directions.length; i++) {
+            direct = directions[i];
+            switch (direct) {
+                case "left":
+                    leftRight.push(direct);
+                    break;
+                case "right":
+                    leftRight.push(direct);
+                    break;
+                case "top":
+                    topBottom.push(direct);
+                    break;
+                case "bottom":
+                    topBottom.push(direct);
+                    break;
+            }
+        }
+        for (i = 0; i < directions.length; i++) {
+            direct = directions[i];
+            switch (direct) {
+                case "left":
+                    if (!isNeedAdaptHeight) {
+                        var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? 0 : extraHeight;
+                        if ($.isLeftSpaceEnough(combo, popup, tW)) {
+                            left = $.getLeftPosition(combo, popup, tW).left;
+                            if (topBottom[0] === "bottom") {
+                                pos = $.getTopAlignPosition(combo, popup, tH, needAdaptHeight);
+                                pos.dir = "left,bottom";
+                            } else {
+                                pos = $.getBottomAlignPosition(combo, popup, tH, needAdaptHeight);
+                                pos.dir = "left,top";
+                            }
+                            if (tbFirst) {
+                                pos.change = "left";
+                            }
+                            pos.left = left;
+                            return pos;
+                        }
+                    }
+                    lrFirst = true;
+                    break;
+                case "right":
+                    if (!isNeedAdaptHeight) {
+                        var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? extraWidth : extraHeight;
+                        if ($.isRightSpaceEnough(combo, popup, tW)) {
+                            left = $.getRightPosition(combo, popup, tW).left;
+                            if (topBottom[0] === "bottom") {
+                                pos = $.getTopAlignPosition(combo, popup, tH, needAdaptHeight);
+                                pos.dir = "right,bottom";
+                            } else {
+                                pos = $.getBottomAlignPosition(combo, popup, tH, needAdaptHeight);
+                                pos.dir = "right,top";
+                            }
+                            if (tbFirst) {
+                                pos.change = "right";
+                            }
+                            pos.left = left;
+                            return pos;
+                        }
+                    }
+                    lrFirst = true;
+                    break;
+                case "top":
+                    var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight;
+                    if ($.isTopSpaceEnough(combo, popup, tH)) {
+                        top = $.getTopPosition(combo, popup, tH).top;
+                        if (leftRight[0] === "right") {
+                            pos = $.getLeftAlignPosition(combo, popup, tW, needAdaptHeight);
+                            pos.dir = "top,right";
+                        } else {
+                            pos = $.getRightAlignPosition(combo, popup, tW);
+                            pos.dir = "top,left";
+                        }
+                        if (lrFirst) {
+                            pos.change = "top";
+                        }
+                        pos.top = top;
+                        return pos;
+                    }
+                    if (needAdaptHeight) {
+                        isNeedAdaptHeight = true;
+                    }
+                    tbFirst = true;
+                    break;
+                case "bottom":
+                    var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight;
+                    if ($.isBottomSpaceEnough(combo, popup, tH)) {
+                        top = $.getBottomPosition(combo, popup, tH).top;
+                        if (leftRight[0] === "right") {
+                            pos = $.getLeftAlignPosition(combo, popup, tW, needAdaptHeight);
+                            pos.dir = "bottom,right";
+                        } else {
+                            pos = $.getRightAlignPosition(combo, popup, tW);
+                            pos.dir = "bottom,left";
+                        }
+                        if (lrFirst) {
+                            pos.change = "bottom";
+                        }
+                        pos.top = top;
+                        return pos;
+                    }
+                    if (needAdaptHeight) {
+                        isNeedAdaptHeight = true;
+                    }
+                    tbFirst = true;
+                    break;
+            }
+        }
+
+        switch (directions[0]) {
+            case "left":
+            case "right":
+                if ($.isRightSpaceLarger(combo)) {
+                    left = $.getRightAdaptPosition(combo, popup, extraWidth).left;
+                } else {
+                    left = $.getLeftAdaptPosition(combo, popup, extraWidth).left;
+                }
+                if (topBottom[0] === "bottom") {
+                    pos = $.getTopAlignPosition(combo, popup, extraHeight, needAdaptHeight);
+                    pos.left = left;
+                    pos.dir = directions[0] + ",bottom";
+                    return pos;
+                }
+                pos = $.getBottomAlignPosition(combo, popup, extraHeight, needAdaptHeight);
+                pos.left = left;
+                pos.dir = directions[0] + ",top";
+                return pos;
+            default :
+                if ($.isBottomSpaceLarger(combo)) {
+                    pos = $.getBottomAdaptPosition(combo, popup, extraHeight, needAdaptHeight);
+                } else {
+                    pos = $.getTopAdaptPosition(combo, popup, extraHeight, needAdaptHeight);
+                }
+                if (leftRight[0] === "right") {
+                    left = $.getLeftAlignPosition(combo, popup, extraWidth, needAdaptHeight).left;
+                    pos.left = left;
+                    pos.dir = directions[0] + ",right";
+                    return pos;
+                }
+                left = $.getRightAlignPosition(combo, popup, extraWidth).left;
+                pos.left = left;
+                pos.dir = directions[0] + ",left";
+                return pos;
+        }
+    },
+
+
+    getComboPosition: function (combo, popup, extraWidth, extraHeight, needAdaptHeight, directions, offsetStyle) {
+        extraWidth || (extraWidth = 0);
+        extraHeight || (extraHeight = 0);
+        var maxHeight = $("body").bounds().height - extraHeight;
+        maxHeight = Math.min(popup.attr("maxHeight") || maxHeight, maxHeight);
+        popup.resetHeight && popup.resetHeight(maxHeight);
+        var position = $.getComboPositionByDirections(combo, popup, extraWidth, extraHeight, needAdaptHeight, directions || ['bottom', 'top', 'right', 'left']);
+        switch (offsetStyle) {
+            case "center":
+                if (position.change) {
+                    var p = $.getMiddleAdaptPosition(combo, popup);
+                    position.top = p.top;
+                } else {
+                    var p = $.getCenterAdaptPosition(combo, popup);
+                    position.left = p.left;
+                }
+                break;
+            case "middle":
+                if (position.change) {
+                    var p = $.getCenterAdaptPosition(combo, popup);
+                    position.left = p.left;
+                } else {
+                    var p = $.getMiddleAdaptPosition(combo, popup);
+                    position.top = p.top;
+                }
+                break;
+        }
+        return position;
+    }
+});/**
+ * 基本的函数
+ * Created by GUY on 2015/6/24.
+ */
+$(function () {
+    BI.Func = {};
+    var formulas = {};
+    BI.extend(BI.Func, {
+        /**
+         * 创建唯一的名字
+         * @param array
+         * @param name
+         * @returns {*}
+         */
+        createDistinctName: function (array, name) {
+            var src = name, idx = 1;
+            name = name || "";
+            while (true) {
+                if (!ArrayUtils.getItemByName(array, name)) {
+                    break;
+                }
+                name = src + (idx++);
+            }
+            return name;
+        },
+
+        /**
+         * 获取搜索结果
+         * @param items
+         * @param keyword
+         * @param param  搜索哪个属性
+         */
+        getSearchResult: function (items, keyword, param) {
+            var isArray = BI.isArray(items);
+            items = isArray ? BI.flatten(items) : items;
+            param || (param = "text");
+            if (!BI.isKey(keyword)) {
+                return {
+                    finded: BI.deepClone(items),
+                    matched: isArray ? [] : {}
+                };
+            }
+            var t, text, py;
+            keyword = BI.toUpperCase(keyword);
+            var matched = isArray ? [] : {}, finded = isArray ? [] : {};
+            BI.each(items, function (i, item) {
+                item = BI.deepClone(item);
+                t = BI.stripEL(item);
+                text = t[param] || t.text || t.value || t.name || t;
+                py = BI.makeFirstPY(text);
+                text = BI.toUpperCase(text);
+                py = BI.toUpperCase(py);
+                var pidx;
+                if (text.indexOf(keyword) > -1) {
+                    if (text === keyword) {
+                        isArray ? matched.push(item) : (matched[i] = item);
+                    } else {
+                        isArray ? finded.push(item) : (finded[i] = item);
+                    }
+                } else if (pidx = py.indexOf(keyword), (pidx > -1 && Math.floor(pidx / text.length) === Math.floor((pidx + keyword.length - 1) / text.length))) {
+                    if (text === keyword || keyword.length === text.length) {
+                        isArray ? matched.push(item) : (matched[i] = item);
+                    } else {
+                        isArray ? finded.push(item) : (finded[i] = item);
+                    }
+                }
+            });
+            return {
+                matched: matched,
+                finded: finded
+            }
+        },
+
+        /**
+         * 公式合法性验证
+         */
+        checkFormulaValidation: function (str) {
+            if (!BI.isEmptyString(str)) {
+                if (BI.has(formulas, str)) {
+                    return formulas[str];
+                }
+                formulas[str] = false;
+                var response = BI.requestSync("fr_bi_base", "check_validation_of_expression", {expression: str});
+                if (response.validation === "invalid") {
+                    formulas[str] = false;
+                } else if (response.validation === "valid") {
+                    formulas[str] = true;
+                }
+                return formulas[str];
+            } else {
+                return true;
+            }
+        },
+
+        getFormulaStringFromFormulaValue: function (formulaValue) {
+            var formulaString = "";
+            var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)/g;
+            var result = formulaValue.match(regx);
+            BI.each(result, function (i, item) {
+                var fieldRegx = /\$[\{][^\}]*[\}]/;
+                var str = item.match(fieldRegx);
+                if (BI.isNotEmptyArray(str)) {
+                    formulaString = formulaString + str[0].substring(2, item.length - 1);
+                } else {
+                    formulaString = formulaString + item;
+                }
+            });
+            return formulaString;
+        },
+
+        formatAddress: function (address) {
+            var temp = '';
+            var url1 = /[a-zA-z]+:\/\/[^\s]*/;
+            var url2 = /\/[^\s]*/;
+            if (address.match(url1) || address.match(url2)) {
+                temp = address;
+            } else if (BI.isNotEmptyString(address)) {
+                temp = "http://" + address;
+            }
+            return temp;
+        },
+
+        getCompleteImageUrl: function (url) {
+            return FR.servletURL + "?op=fr_bi&cmd=get_uploaded_image&image_id=" + url;
+        }
+
+    });
+
+    /**
+     * 对DOM操作的通用函数
+     * @type {{}}
+     */
+    BI.DOM = {};
+    BI.extend(BI.DOM, {
+
+        /**
+         * 把dom数组或元素悬挂起来,使其不对html产生影响
+         * @param dom
+         */
+        hang: function (doms) {
+            if (BI.isEmpty(doms)) {
+                return;
+            }
+            var frag = document.createDocumentFragment();
+            BI.each(doms, function (i, dom) {
+                dom instanceof BI.Widget && (dom = dom.element);
+                dom instanceof $ && dom[0] && frag.appendChild(dom[0]);
+            });
+            return frag;
+        },
+
+        isExist: function (obj) {
+            return $("body").find(obj.element).length > 0;
+        },
+
+        //预加载图片
+        preloadImages: function (srcArray, onload) {
+            var count = 0, images = [];
+
+            function complete() {
+                count++;
+                if (count >= srcArray.length) {
+                    onload();
+                }
+            }
+
+            BI.each(srcArray, function (i, src) {
+                images[i] = new Image();
+                images[i].src = src;
+                images[i].onload = function () {
+                    complete()
+                };
+                images[i].onerror = function () {
+                    complete()
+                };
+            });
+        },
+
+        getImageWidthAndHeight: function (src) {
+            return BI.requestSync("fr_bi_base", "get_image_size", {
+                src: src
+            });
+        },
+
+        isDarkColor: function (hex) {
+            if (!hex) {
+                return false;
+            }
+            var rgb = this.rgb2json(this.hex2rgb(hex));
+            var grayLevel = (rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);
+            if (grayLevel < 192) {
+                return true;
+            }
+            return false;
+        },
+
+        rgb2hex: function (rgbColour) {
+            if (!rgbColour || rgbColour.substr(0, 3) != "rgb") {
+                return "";
+            }
+            var rgbValues = rgbColour.match(/\d+(\.\d+)?/g);
+            var red = BI.parseInt(rgbValues[0]);
+            var green = BI.parseInt(rgbValues[1]);
+            var blue = BI.parseInt(rgbValues[2]);
+
+            var hexColour = "#" + this.int2hex(red) + this.int2hex(green) + this.int2hex(blue);
+
+            return hexColour;
+        },
+
+        rgb2json: function (rgbColour) {
+            if (!rgbColour) {
+                return {};
+            }
+            var rgbValues = rgbColour.match(/\d+(\.\d+)?/g);
+            return {
+                r: BI.parseInt(rgbValues[0]),
+                g: BI.parseInt(rgbValues[1]),
+                b: BI.parseInt(rgbValues[2])
+            };
+        },
+
+        rgba2json: function (rgbColour) {
+            if (!rgbColour) {
+                return {};
+            }
+            var rgbValues = rgbColour.match(/\d+(\.\d+)?/g);
+            return {
+                r: BI.parseInt(rgbValues[0]),
+                g: BI.parseInt(rgbValues[1]),
+                b: BI.parseInt(rgbValues[2]),
+                a: BI.parseFloat(rgbValues[3])
+            };
+        },
+
+        json2rgb: function (rgb) {
+            if (!BI.isKey(rgb.r) || !BI.isKey(rgb.g) || !BI.isKey(rgb.b)) {
+                return "";
+            }
+            return "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
+        },
+
+        json2rgba: function (rgba) {
+            if (!BI.isKey(rgba.r) || !BI.isKey(rgba.g) || !BI.isKey(rgba.b)) {
+                return "";
+            }
+            return "rgba(" + rgba.r + "," + rgba.g + "," + rgba.b + "," + rgba.a + ")";
+        },
+
+        int2hex: function (strNum) {
+            var hexdig = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+
+            return hexdig[strNum >>> 4] + '' + hexdig[strNum & 15];
+        },
+
+        hex2rgb: function (color) {
+            if (!color) {
+                return "";
+            }
+            var tempValue = "rgb(", colorArray;
+
+            if (color.length === 7) {
+                colorArray = [BI.parseInt('0x' + color.substring(1, 3)),
+                    BI.parseInt('0x' + color.substring(3, 5)),
+                    BI.parseInt('0x' + color.substring(5, 7))];
+            }
+            else if (color.length === 4) {
+                colorArray = [BI.parseInt('0x' + color.substring(1, 2)),
+                    BI.parseInt('0x' + color.substring(2, 3)),
+                    BI.parseInt('0x' + color.substring(3, 4))];
+            }
+            tempValue += colorArray[0] + ",";
+            tempValue += colorArray[1] + ",";
+            tempValue += colorArray[2] + ")";
+
+            return tempValue;
+        },
+
+        rgba2rgb: function (rgbColour, BGcolur) {
+            if (BI.isNull(BGcolur)) {
+                BGcolur = 1;
+            }
+            if (rgbColour.substr(0, 4) != "rgba") {
+                return "";
+            }
+            var rgbValues = rgbColour.match(/\d+(\.\d+)?/g);
+            if (rgbValues.length < 4) {
+                return "";
+            }
+            var R = BI.parseFloat(rgbValues[0]);
+            var G = BI.parseFloat(rgbValues[1]);
+            var B = BI.parseFloat(rgbValues[2]);
+            var A = BI.parseFloat(rgbValues[3]);
+
+            return "rgb(" + Math.floor(255 * (BGcolur * (1 - A )) + R * A) + "," +
+                Math.floor(255 * (BGcolur * (1 - A )) + G * A) + "," +
+                Math.floor(255 * (BGcolur * (1 - A )) + B * A) + ")";
+        },
+
+        getTextSizeWidth: function (text, fontSize) {
+            var span = $("<span></span>").addClass("text-width-span").appendTo($("#container"));
+
+            if (fontSize == null) {
+                fontSize = 12;
+            }
+            fontSize = fontSize + "px";
+
+            span.css("font-size", fontSize).text(text);
+
+            var width = span.width();
+            span.remove();
+
+            return width;
+        },
+
+        //获取滚动条的宽度
+        getScrollWidth: function () {
+            if (this._scrollWidth == null) {
+                var ul = $("<div>").width(50).height(50).css({
+                    position: "absolute",
+                    top: "-9999px",
+                    overflow: "scroll"
+                }).appendTo($("#container"));
+                this._scrollWidth = ul[0].offsetWidth - ul[0].clientWidth;
+                ul.destroy();
+            }
+            return this._scrollWidth;
+        }
+    });
+});/**
+ * guy
+ * 检测某个Widget的EventChange事件然后去show某个card
+ * @type {*|void|Object}
+ * @class BI.ShowListener
+ * @extends BI.OB
+ */
+BI.ShowListener = BI.inherit(BI.OB, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ShowListener.superclass._defaultConfig.apply(this, arguments), {
+            eventObj: BI.createWidget(),
+            cardLayout: null,
+            cardNameCreator: function (v) {
+                return v;
+            },
+            cardCreator: BI.emptyFn,
+            afterCardCreated: BI.emptyFn,
+            afterCardShow: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.ShowListener.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        o.eventObj.on(BI.Controller.EVENT_CHANGE, function (type, v, ob) {
+            if (type === BI.Events.CLICK) {
+                v = v || o.eventObj.getValue();
+                v = BI.isArray(v) ? (v.length > 1 ? v.toString() : v[0]) : v;
+                if (BI.isNull(v)) {
+                    throw new Error("value值不能为空");
+                }
+                var cardName = o.cardNameCreator(v);
+                if (!o.cardLayout.isCardExisted(cardName)) {
+                    var card = o.cardCreator(cardName);
+                    o.cardLayout.addCardByName(cardName, card);
+                    o.afterCardCreated(cardName);
+                }
+                o.cardLayout.showCardByName(cardName);
+                BI.nextTick(function () {
+                    o.afterCardShow(cardName);
+                    self.fireEvent(BI.ShowListener.EVENT_CHANGE, cardName);
+                });
+            }
+        })
+    }
+});
+BI.ShowListener.EVENT_CHANGE = "ShowListener.EVENT_CHANGE";/**
+ * @class BI.Logic
+ * @extends BI.OB
+ */
+BI.Logic = BI.inherit(BI.OB, {
+    createLogic: function () {
+        return this.options || {};
+    }
+});
+
+BI.LogicFactory = {
+    Type: {
+        Vertical: "vertical",
+        Horizontal: "horizontal",
+        Table: "table",
+        HorizontalFill: "horizontal_fill"
+    },
+    createLogic: function (key, options) {
+        var logic;
+        switch (key) {
+            case BI.LogicFactory.Type.Vertical:
+                logic = BI.VerticalLayoutLogic;
+                break;
+            case BI.LogicFactory.Type.Horizontal:
+                logic = BI.HorizontalLayoutLogic;
+                break;
+            case BI.LogicFactory.Type.Table:
+                logic = BI.TableLayoutLogic;
+                break;
+            case BI.LogicFactory.Type.HorizontalFill:
+                logic = BI.HorizontalFillLayoutLogic;
+                break;
+            default :
+                logic = BI.Logic;
+                break;
+        }
+        return new logic(options).createLogic();
+    },
+
+    createLogicTypeByDirection: function (direction) {
+        switch (direction) {
+            case BI.Direction.Top:
+            case BI.Direction.Bottom:
+            case BI.Direction.Custom:
+                return BI.LogicFactory.Type.Vertical;
+                break;
+            case BI.Direction.Left:
+            case BI.Direction.Right:
+                return BI.LogicFactory.Type.Horizontal;
+        }
+    },
+
+    createLogicItemsByDirection: function (direction) {
+        var layout;
+        var items = Array.prototype.slice.call(arguments, 1);
+        items = BI.map(items, function (i, item) {
+            if (BI.isWidget(item)) {
+                return {
+                    el: item,
+                    width: item.options.width,
+                    height: item.options.height
+                }
+            }
+            return item;
+        });
+        switch (direction) {
+            case BI.Direction.Bottom:
+                layout = BI.LogicFactory.Type.Vertical;
+                items.reverse();
+                break;
+            case BI.Direction.Right:
+                layout = BI.LogicFactory.Type.Horizontal;
+                items.reverse();
+                break;
+            case BI.Direction.Custom:
+                items = items.slice(1);
+                break;
+        }
+        return items;
+    }
+};/**
+ * guy
+ * 上下布局逻辑
+ * 上下布局的时候要考虑到是动态布局还是静态布局
+ *
+ * @class BI.VerticalLayoutLogic
+ * @extends BI.Logic
+ */
+BI.VerticalLayoutLogic = BI.inherit(BI.Logic, {
+    _defaultConfig: function () {
+        return BI.extend(BI.VerticalLayoutLogic.superclass._defaultConfig.apply(this, arguments), {
+            dynamic: false,
+            scrollable: null,
+            scrolly: false,
+            scrollx: false,
+            items: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    createLogic: function () {
+        var layout, o = this.options;
+        if (o.dynamic) {
+            layout = "bi.vertical";
+        } else {
+            layout = "bi.vtape";
+        }
+        return {
+            type: layout,
+            scrollable: o.scrollable,
+            scrolly: o.scrolly,
+            scrollx: o.scrollx,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            items: o.items
+        }
+    },
+
+    _init: function () {
+        BI.VerticalLayoutLogic.superclass._init.apply(this, arguments);
+    }
+});
+
+
+/**
+ * guy
+ * 左右布局逻辑
+ * 左右布局的时候要考虑到是动态布局还是静态布局
+ *
+ * @class BI.HorizontalLayoutLogic
+ * @extends BI.Logic
+ */
+BI.HorizontalLayoutLogic = BI.inherit(BI.Logic, {
+    _defaultConfig: function () {
+        return BI.extend(BI.HorizontalLayoutLogic.superclass._defaultConfig.apply(this, arguments), {
+            dynamic: false,
+            scrollable: null,
+            scrolly: false,
+            scrollx: false,
+            items: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    createLogic: function () {
+        var layout, o = this.options;
+        if (o.dynamic) {
+            layout = "bi.horizontal";
+        } else {
+            layout = "bi.htape";
+        }
+        return {
+            type: layout,
+            scrollable: o.scrollable,
+            scrolly: o.scrolly,
+            scrollx: o.scrollx,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            items: o.items
+        }
+    },
+
+    _init: function () {
+        BI.HorizontalLayoutLogic.superclass._init.apply(this, arguments);
+    }
+});
+
+/**
+ * guy
+ * 表格布局逻辑
+ * 表格布局的时候要考虑到是动态布局还是静态布局
+ *
+ * @class BI.TableLayoutLogic
+ * @extends BI.OB
+ */
+BI.TableLayoutLogic = BI.inherit(BI.Logic, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TableLayoutLogic.superclass._defaultConfig.apply(this, arguments), {
+            dynamic: false,
+            scrollable: null,
+            scrolly: false,
+            scrollx: false,
+            columns: 0,
+            rows: 0,
+            columnSize: [],
+            rowSize: [],
+            hgap: 0,
+            vgap: 0,
+            items: []
+        });
+    },
+
+    createLogic: function () {
+        var layout, o = this.options;
+        if (o.dynamic) {
+            layout = "bi.table";
+        } else {
+            layout = "bi.window";
+        }
+        return {
+            type: layout,
+            scrollable: o.scrollable,
+            scrolly: o.scrolly,
+            scrollx: o.scrollx,
+            columns: o.columns,
+            rows: o.rows,
+            columnSize: o.columnSize,
+            rowSize: o.rowSize,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            items: o.items
+        }
+    },
+
+    _init: function () {
+        BI.TableLayoutLogic.superclass._init.apply(this, arguments);
+    }
+});
+
+/**
+ * guy
+ * 左右充满布局逻辑
+ *
+ * @class BI.HorizontalFillLayoutLogic
+ * @extends BI.Logic
+ */
+BI.HorizontalFillLayoutLogic = BI.inherit(BI.Logic, {
+    _defaultConfig: function () {
+        return BI.extend(BI.HorizontalFillLayoutLogic.superclass._defaultConfig.apply(this, arguments), {
+            dynamic: false,
+            scrollable: null,
+            scrolly: false,
+            scrollx: false,
+            items: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    createLogic: function () {
+        var layout, o = this.options;
+        var columnSize = [];
+        BI.each(o.items, function (i, item) {
+            columnSize.push(item.width || 0);
+        });
+        if (o.dynamic) {
+            layout = "bi.horizontal_adapt";
+        } else {
+            layout = "bi.htape";
+        }
+        return {
+            type: layout,
+            columnSize: columnSize,
+            scrollable: o.scrollable,
+            scrolly: o.scrolly,
+            scrollx: o.scrollx,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            items: o.items
+        }
+    },
+
+    _init: function () {
+        BI.HorizontalFillLayoutLogic.superclass._init.apply(this, arguments);
+    }
+});BI.Plugin = BI.Plugin || {};
+;
+(function () {
+    var _WidgetsPlugin = {};
+    var _ObjectPlugin = {};
+    BI.extend(BI.Plugin, {
+
+        getWidget: function (type, options) {
+            if (_WidgetsPlugin[type]) {
+                var res;
+                for (var i = _WidgetsPlugin[type].length-1; i >=0; i--) {
+                    if (res = _WidgetsPlugin[type][i](options)) {
+                        return res;
+                    }
+                }
+            }
+            return options;
+        },
+
+        registerWidget: function (type, fn) {
+            if (!_WidgetsPlugin[type]) {
+                _WidgetsPlugin[type] = [];
+            }
+            if (_WidgetsPlugin[type].length > 0) {
+                console.log("组件已经注册过了!");
+            }
+            _WidgetsPlugin[type].push(fn);
+        },
+
+        relieveWidget: function (type) {
+            delete _WidgetsPlugin[type];
+        },
+
+        getObject: function (type, object) {
+            if (_ObjectPlugin[type]) {
+                var res;
+                for (var i = 0, len = _ObjectPlugin[type].length; i < len; i++) {
+                    res = _ObjectPlugin[type][i](object);
+                }
+            }
+            return res || object;
+        },
+
+        registerObject: function (type, fn) {
+            if (!_ObjectPlugin[type]) {
+                _ObjectPlugin[type] = [];
+            }
+            if (_ObjectPlugin[type].length > 0) {
+                console.log("对象已经注册过了!");
+            }
+            _ObjectPlugin[type].push(fn);
+        },
+
+        relieveObject: function (type) {
+            delete _ObjectPlugin[type];
+        }
+    });
+})();/**
+ * 对数组对象的扩展
+ * @class Array
+ */
+$.extend(Array.prototype, {
+    /**
+     * 检查指定的值是否在数组中
+     * @param {Object} o 要检查的值
+     * @return {Number}  o在数组中的索引(如果不在数组中则返回-1)
+     */
+    indexOf: function (o) {
+        for (var i = 0, len = this.length; i < len; i++) {
+            if (_.isEqual(o, this[i])) {
+                return i;
+            }
+        }
+        return -1;
+    },
+
+    /**
+     * 检查指定的值是否在数组中
+     * ie67不支持数组的这个方法
+     * @param {Object} o 要检查的值
+     * @return {Number}  o在数组中的索引(如果不在数组中则返回-1)
+     */
+    lastIndexOf: function (o) {
+        for (var len = this.length, i = len - 1; i >= 0; i--) {
+            if (_.isEqual(o, this[i])) {
+                return i;
+            }
+        }
+        return -1;
+    },
+
+    /**
+     * 从数组中移除指定的值,如果值不在数组中,则不产生任何效果
+     * @param {Object} o 要移除的值
+     * @return {Array} 移除制定值后的数组
+     */
+    remove: function (o) {
+        var index = this.indexOf(o);
+        if (index != -1) {
+            this.splice(index, 1);
+        }
+        return this;
+    },
+    /**
+     * 移除数组中的所有元素
+     */
+    clear: function () {
+        while (this.length > 0) {
+            this.pop();
+        }
+    }
+});
+
+/**
+ * Array原型拓展
+ * Created by wang on 15/6/23.
+ */
+!function () {
+    _.each(['contains', 'indexOf', 'lastIndexOf'], function (name) {
+        Array.prototype[name] = function () {
+            var arr = _.toArray(arguments);
+            arr.unshift(this);
+            return BI[name].apply(this, arr);
+        };
+    });
+    Array.prototype.pushArray = function (array) {
+        for (var i = 0; i < array.length; i++) {
+            this.push(array[i]);
+        }
+    };
+    Array.prototype.pushDistinct = function (obj) {
+        if (!this.contains(obj)) {
+            this.push(obj);
+        }
+    };
+    Array.prototype.pushDistinctArray = function (array) {
+        for (var i = 0, len = array.length; i < len; i++) {
+            this.pushDistinct(array[i]);
+        }
+    };
+}();
+
+/**
+ * 规定bi的数组分为两种,其中,value和type值为key值
+ * 1、[{"text":1,"value":2,"children":[]}]
+ * 2、[{"name":1,"type":2,"children":[]}]
+ * guy
+ * 对数组的操作
+ * @type {{}}
+ */
+ArrayUtils = {};
+
+$.extend(ArrayUtils, {
+    /**
+     * 遍历方法
+     * @param array
+     * @param back
+     */
+    traversal: function (array, back) {
+        if (BI.isNull(array)) {
+            return;
+        }
+        var self = this;
+        BI.each(array, function (i, item) {
+            if (back(i, item) === BI.Status.END) {
+                return false;
+            }
+            self.traversal(item.children, back);
+        })
+    },
+
+    getAllChildNames: function (array) {
+        var names = [];
+        this.traversal(array, function (i, item) {
+            if (BI.isNotEmptyArray(item.children)) {
+                return BI.Status.RUNNING;
+            }
+            names.push(item.text || item.name);
+        });
+        return names;
+    },
+
+    /**
+     * 获取第一个子节点
+     * @param array
+     */
+    getFirstChild: function (array) {
+        var first = {};
+        this.traversal(array, function (i, item) {
+            if (BI.isNotEmptyArray(item.children)) {
+                return;
+            }
+            first = item;
+            return BI.Status.END;
+        })
+        return first;
+    },
+
+    /**
+     * 获取最后一个子节点
+     * @param array
+     */
+    getLastChild: function (array) {
+        var first = {};
+        this.traversal(array, function (i, item) {
+            if (item.children && item.children.length > 0) {
+                return;
+            }
+            first = item;
+        })
+        return first;
+    },
+
+    getTextByValue: function (array, value) {
+        if (!array) {
+            return value;
+        }
+        var text = "";
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.value, value)) {
+                text = item.text;
+                return BI.Status.END;
+            }
+        });
+        return text;
+    },
+
+    getNameByType: function (array, type) {
+        if (!array) {
+            return type;
+        }
+        var name = "";
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.type, type)) {
+                name = item.name;
+                return BI.Status.END;
+            }
+        });
+        return name;
+    },
+
+    getItemByText: function (array, text) {
+        var res = void 0;
+        this.traversal(array, function (i, item) {
+            if (BI.isCapitalEqual(item.text, text)) {
+                res = item;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getIndexByText: function (array, text) {
+        var res = -1;
+        this.traversal(array, function (i, item) {
+            if (BI.isCapitalEqual(item.text, text)) {
+                res = i;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getItemByValue: function (array, value) {
+        var res = void 0;
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.value, value)) {
+                res = item;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getIndexByValue: function (array, value) {
+        var res = -1;
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.value, value)) {
+                res = i;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getItemByName: function (array, name) {
+        var res = void 0;
+        this.traversal(array, function (i, item) {
+            if (BI.isCapitalEqual(item.name, name)) {
+                res = item;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getIndexByName: function (array, name) {
+        var res = -1;
+        this.traversal(array, function (i, item) {
+            if (BI.isCapitalEqual(item.name, name)) {
+                res = i;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getItemByType: function (array, type) {
+        var res = void 0;
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.type, type)) {
+                res = item;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    getIndexByType: function (array, type) {
+        var res = -1;
+        this.traversal(array, function (i, item) {
+            if (BI.isEqual(item.type, type)) {
+                res = i;
+                return BI.Status.END;
+            }
+        });
+        return res;
+    },
+
+    deleteItemByType: function (array, type) {
+        var item = this.getItemByType(array, type);
+        array.remove(item);
+    },
+
+    deleteItemByName: function (array, name) {
+        var item = this.getItemByName(array, name);
+        array.remove(item);
+    },
+
+    deleteItemByValue: function (array, value) {
+        var item = this.getItemByValue(array, value);
+        array.remove(item);
+    }
+});/*
+ * 前端缓存
+ */
+window.localStorage || (window.localStorage = {
+    items: {},
+    setItem: function (k, v) {
+        BI.Cache.addCookie(k, v);
+    },
+    getItem: function (k) {
+        return BI.Cache.getCookie(k);
+    },
+    removeItem: function (k) {
+        BI.Cache.deleteCookie(k);
+    },
+    key: function () {
+
+    },
+    clear: function () {
+        this.items = {};
+    }
+});
+BI.Cache = {
+    _prefix: "bi",
+    setUsername: function (username) {
+        localStorage.setItem(BI.Cache._prefix + ".username", (username + "" || "").toUpperCase());
+    },
+    getUsername: function () {
+        return localStorage.getItem(BI.Cache._prefix + ".username") || "";
+    },
+    _getKeyPrefix: function () {
+        return BI.Cache.getUsername() + "." + BI.Cache._prefix + ".";
+    },
+    _generateKey: function (key) {
+        return BI.Cache._getKeyPrefix() + (key || "");
+    },
+    getItem: function (key) {
+        return localStorage.getItem(BI.Cache._generateKey(key));
+    },
+    setItem: function (key, value) {
+        localStorage.setItem(BI.Cache._generateKey(key), value);
+    },
+    removeItem: function (key) {
+        localStorage.removeItem(BI.Cache._generateKey(key));
+    },
+    clear: function () {
+        for (var i = localStorage.length; i >= 0; i--) {
+            var key = localStorage.key(i);
+            if (key) {
+                if (key.indexOf(BI.Cache._getKeyPrefix()) === 0) {
+                    localStorage.removeItem(key);
+                }
+            }
+        }
+    },
+    keys: function () {
+        var result = [];
+        for (var i = localStorage.length; i >= 0; i--) {
+            var key = localStorage.key(i);
+            if (key) {
+                var prefix = BI.Cache._getKeyPrefix();
+                if (key.indexOf(prefix) === 0) {
+                    result[result.length] = key.substring(prefix.length);
+                }
+            }
+        }
+        return result;
+    },
+
+    addCookie: function (name, value, path, expiresHours) {
+        var cookieString = name + "=" + escape(value);
+        // 判断是否设置过期时间
+        if (expiresHours && expiresHours > 0) {
+            var date = new Date();
+            date.setTime(date.getTime() + expiresHours * 3600 * 1000);
+            cookieString = cookieString + "; expires=" + date.toGMTString();
+        }
+        if (path) {
+            cookieString = cookieString + "; path=" + path;
+        }
+        document.cookie = cookieString;
+    },
+    getCookie: function (name) {
+        var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
+        if (arr = document.cookie.match(reg))
+            return unescape(arr[2]);
+        else
+            return null;
+    },
+    deleteCookie: function (name, path) {
+        var date = new Date();
+        date.setTime(date.getTime() - 10000);
+        var cookieString = name + "=v; expires=" + date.toGMTString();
+        if (path) {
+            cookieString = cookieString + "; path=" + path;
+        }
+        document.cookie = cookieString;
+    }
+};// full day names
+Date._DN = [BI.i18nText("BI-Sunday"),
+    BI.i18nText("BI-Monday"),
+    BI.i18nText("BI-Tuesday"),
+    BI.i18nText("BI-Wednesday"),
+    BI.i18nText("BI-Thursday"),
+    BI.i18nText("BI-Friday"),
+    BI.i18nText("BI-Saturday"),
+    BI.i18nText("BI-Sunday")];
+
+// short day names
+Date._SDN = ['日',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    ''];
+
+// Monday first, etc.
+Date._FD = 1;
+
+// full month names
+Date._MN = [
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    ''];
+
+// short month names
+Date._SMN = ['',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    '',
+    ''];
+
+Date._QN = ["", BI.i18nText("BI-Quarter_1"),
+    BI.i18nText("BI-Quarter_2"),
+    BI.i18nText("BI-Quarter_3"),
+    BI.i18nText("BI-Quarter_4")];
+
+
+
+/** Adds the number of days array to the Date object. */
+Date._MD = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+
+/** Constants used for time computations */
+Date.SECOND = 1000 /* milliseconds */;
+Date.MINUTE = 60 * Date.SECOND;
+Date.HOUR = 60 * Date.MINUTE;
+Date.DAY = 24 * Date.HOUR;
+Date.WEEK = 7 * Date.DAY;
+
+/** Returns the number of days in the current month */
+Date.prototype.getMonthDays = function (month) {
+    var year = this.getFullYear();
+    if (typeof month == "undefined") {
+        month = this.getMonth();
+    }
+    if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1) {
+        return 29;
+    } else {
+        return Date._MD[month];
+    }
+};
+
+/** Returns the number of day in the year. */
+Date.prototype.getDayOfYear = function () {
+    var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+    var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
+    var time = now - then;
+    return Math.floor(time / Date.DAY);
+};
+
+/** Returns the number of the week in year, as defined in ISO 8601. */
+Date.prototype.getWeekNumber = function () {
+    var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+    var DoW = d.getDay();
+    d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
+    var ms = d.valueOf(); // GMT
+    d.setMonth(0);
+    d.setDate(4); // Thu in Week 1
+    return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
+};
+
+//离当前时间多少天的时间
+Date.prototype.getOffsetDate = function (offset) {
+    return new Date(this.getTime() + offset * 864e5);
+};
+
+/** Checks date and time equality */
+Date.prototype.equalsTo = function (date) {
+    return ((this.getFullYear() == date.getFullYear()) &&
+    (this.getMonth() == date.getMonth()) &&
+    (this.getDate() == date.getDate()) &&
+    (this.getHours() == date.getHours()) &&
+    (this.getMinutes() == date.getMinutes()) &&
+    (this.getSeconds() == date.getSeconds()));
+};
+
+/** Set only the year, month, date parts (keep existing time) */
+Date.prototype.setDateOnly = function (date) {
+    var tmp = new Date(date);
+    this.setDate(1);
+    this.setFullYear(tmp.getFullYear());
+    this.setMonth(tmp.getMonth());
+    this.setDate(tmp.getDate());
+};
+/** Prints the date in a string according to the given format. */
+Date.prototype.print = function (str) {
+    var m = this.getMonth();
+    var d = this.getDate();
+    var y = this.getFullYear();
+    var wn = this.getWeekNumber();
+    var w = this.getDay();
+    var s = {};
+    var hr = this.getHours();
+    var pm = (hr >= 12);
+    var ir = (pm) ? (hr - 12) : hr;
+    var dy = this.getDayOfYear();
+    if (ir == 0) {
+        ir = 12;
+    }
+    var min = this.getMinutes();
+    var sec = this.getSeconds();
+    s["%a"] = Date._SDN[w]; // abbreviated weekday name [FIXME: I18N]
+    s["%A"] = Date._DN[w]; // full weekday name
+    s["%b"] = Date._SMN[m]; // abbreviated month name [FIXME: I18N]
+    s["%B"] = Date._MN[m]; // full month name
+    // FIXME: %c : preferred date and time representation for the current locale
+    s["%C"] = 1 + Math.floor(y / 100); // the century number
+    s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
+    s["%e"] = d; // the day of the month (range 1 to 31)
+    // FIXME: %D : american date style: %m/%d/%y
+    // FIXME: %E, %F, %G, %g, %h (man strftime)
+    s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
+    s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
+    s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
+    s["%k"] = hr;		// hour, range 0 to 23 (24h format)
+    s["%l"] = ir;		// hour, range 1 to 12 (12h format)
+    s["%X"] = (m < 9) ? ("0" + (1 + m)) : (1 + m); // month, range 01 to 12
+    s["%x"] = m + 1 // month, range 1 to 12
+    s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
+    s["%n"] = "\n";		// a newline character
+    s["%p"] = pm ? "PM" : "AM";
+    s["%P"] = pm ? "pm" : "am";
+    // FIXME: %r : the time in am/pm notation %I:%M:%S %p
+    // FIXME: %R : the time in 24-hour notation %H:%M
+    s["%s"] = Math.floor(this.getTime() / 1000);
+    s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
+    s["%t"] = "\t";		// a tab character
+    // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
+    s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
+    s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
+    s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
+    // FIXME: %x : preferred date representation for the current locale without the time
+    // FIXME: %X : preferred time representation for the current locale without the date
+    s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
+    s["%Y"] = y;		// year with the century
+    s["%%"] = "%";		// a literal '%' character
+
+    var re = /%./g;
+    if (!BI.isKhtml()) {
+        return str.replace(re, function (par) {
+            return s[par] || par;
+        });
+    }
+
+    var a = str.match(re);
+    for (var i = 0; i < a.length; i++) {
+        var tmp = s[a[i]];
+        if (tmp) {
+            re = new RegExp(a[i], 'g');
+            str = str.replace(re, tmp);
+        }
+    }
+
+    return str;
+};
+
+/**
+ * 是否是闰年
+ * @param year
+ * @returns {boolean}
+ */
+Date.isLeap = function (year) {
+    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+};
+
+/**
+ * 检测是否在有效期
+ *
+ * @param YY 年
+ * @param MM 月
+ * @param DD 日
+ * @param minDate '1900-01-01'
+ * @param maxDate '2099-12-31'
+ * @returns {Array} 若无效返回无效状态
+ */
+Date.checkVoid = function (YY, MM, DD, minDate, maxDate) {
+    var back = [];
+    YY = YY | 0;
+    MM = MM | 0;
+    DD = DD | 0;
+    minDate = BI.isString(minDate) ? minDate.match(/\d+/g) : minDate;
+    maxDate = BI.isString(maxDate) ? maxDate.match(/\d+/g) : maxDate;
+    if (YY < minDate[0]) {
+        back = ['y'];
+    } else if (YY > maxDate[0]) {
+        back = ['y', 1];
+    } else if (YY >= minDate[0] && YY <= maxDate[0]) {
+        if (YY == minDate[0]) {
+            if (MM < minDate[1]) {
+                back = ['m'];
+            } else if (MM == minDate[1]) {
+                if (DD < minDate[2]) {
+                    back = ['d'];
+                }
+            }
+        }
+        if (YY == maxDate[0]) {
+            if (MM > maxDate[1]) {
+                back = ['m', 1];
+            } else if (MM == maxDate[1]) {
+                if (DD > maxDate[2]) {
+                    back = ['d', 1];
+                }
+            }
+        }
+    }
+    return back;
+};
+
+Date.checkLegal = function (str) {
+    var ar = str.match(/\d+/g);
+    var YY = ar[0] | 0, MM = ar[1] | 0, DD = ar[2] | 0;
+    if (ar.length <= 1) {
+        return true;
+    }
+    if (ar.length <= 2) {
+        return MM >= 1 && MM <= 12;
+    }
+    Date._MD[1] = Date.isLeap(YY) ? 29 : 28;
+    return MM >= 1 && MM <= 12 && DD <= Date._MD[MM - 1];
+};
+
+Date.parseDateTime = function (str, fmt) {
+    var today = new Date();
+    var y = 0;
+    var m = 0;
+    var d = 1;
+    //wei : 对于fmt为‘YYYYMM’或者‘YYYYMMdd’的格式,str的值为类似'201111'的形式,因为年月之间没有分隔符,所以正则表达式分割无效,导致bug7376。
+    var a = str.split(/\W+/);
+    if (fmt.toLowerCase() == '%y%x' || fmt.toLowerCase() == '%y%x%d') {
+        var yearlength = 4;
+        var otherlength = 2;
+        a[0] = str.substring(0, yearlength);
+        a[1] = str.substring(yearlength, yearlength + otherlength);
+        a[2] = str.substring(yearlength + otherlength, yearlength + otherlength * 2);
+    }
+    var b = fmt.match(/%./g);
+    var i = 0, j = 0;
+    var hr = 0;
+    var min = 0;
+    var sec = 0;
+    for (i = 0; i < a.length; ++i) {
+        switch (b[i]) {
+            case "%d":
+            case "%e":
+                d = parseInt(a[i], 10);
+                break;
+
+            case "%X":
+                m = parseInt(a[i], 10) - 1;
+                break;
+            case "%x":
+                m = parseInt(a[i], 10) - 1;
+                break;
+
+            case "%Y":
+            case "%y":
+                y = parseInt(a[i], 10);
+                (y < 100) && (y += (y > 29) ? 1900 : 2000);
+                break;
+
+            case "%b":
+            case "%B":
+                for (j = 0; j < 12; ++j) {
+                    if (Date._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
+                        m = j;
+                        break;
+                    }
+                }
+                break;
+
+            case "%H":
+            case "%I":
+            case "%k":
+            case "%l":
+                hr = parseInt(a[i], 10);
+                break;
+
+            case "%P":
+            case "%p":
+                if (/pm/i.test(a[i]) && hr < 12) {
+                    hr += 12;
+                } else if (/am/i.test(a[i]) && hr >= 12) {
+                    hr -= 12;
+                }
+                break;
+
+            case "%M":
+                min = parseInt(a[i], 10);
+            case "%S":
+                sec = parseInt(a[i], 10);
+                break;
+        }
+    }
+//    if (!a[i]) {
+//        continue;
+//	}
+    if (isNaN(y)) {
+        y = today.getFullYear();
+    }
+    if (isNaN(m)) {
+        m = today.getMonth();
+    }
+    if (isNaN(d)) {
+        d = today.getDate();
+    }
+    if (isNaN(hr)) {
+        hr = today.getHours();
+    }
+    if (isNaN(min)) {
+        min = today.getMinutes();
+    }
+    if (isNaN(sec)) {
+        sec = today.getSeconds();
+    }
+    if (y != 0) {
+        return new Date(y, m, d, hr, min, sec);
+    }
+    y = 0;
+    m = -1;
+    d = 0;
+    for (i = 0; i < a.length; ++i) {
+        if (a[i].search(/[a-zA-Z]+/) != -1) {
+            var t = -1;
+            for (j = 0; j < 12; ++j) {
+                if (Date._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
+                    t = j;
+                    break;
+                }
+            }
+            if (t != -1) {
+                if (m != -1) {
+                    d = m + 1;
+                }
+                m = t;
+            }
+        } else if (parseInt(a[i], 10) <= 12 && m == -1) {
+            m = a[i] - 1;
+        } else if (parseInt(a[i], 10) > 31 && y == 0) {
+            y = parseInt(a[i], 10);
+            (y < 100) && (y += (y > 29) ? 1900 : 2000);
+        } else if (d == 0) {
+            d = a[i];
+        }
+    }
+    if (y == 0) {
+        y = today.getFullYear();
+    }
+    if (m != -1 && d != 0) {
+        return new Date(y, m, d, hr, min, sec);
+    }
+    return today;
+};/*
+ * 给jQuery.Event对象添加的工具方法
+ */
+$.extend($.Event.prototype, {
+    // event.stopEvent
+    stopEvent: function () {
+        this.stopPropagation();
+        this.preventDefault();
+    }
+});Function.prototype.before = function (func) {
+    var __self = this;
+    return function () {
+        if (func.apply(this, arguments) === false) {
+            return false;
+        }
+        return __self.apply(this, arguments);
+    }
+};
+
+Function.prototype.after = function (func) {
+    var __self = this;
+    return function () {
+        var ret = __self.apply(this, arguments);
+        if (ret === false) {
+            return false;
+        }
+        func.apply(this, arguments);
+        return ret;
+    }
+};if (!Number.prototype.toFixed || (0.00008).toFixed(3) !== '0.000' ||
+    (0.9).toFixed(0) === '0' || (1.255).toFixed(2) !== '1.25' ||
+    (1000000000000000128).toFixed(0) !== "1000000000000000128") {
+    (function () {
+        var base, size, data, i;
+        base = 1e7;
+        size = 6;
+        data = [0, 0, 0, 0, 0, 0];
+        function multiply(n, c) {
+            var i = -1;
+            while (++i < size) {
+                c += n * data[i];
+                data[i] = c % base;
+                c = Math.floor(c / base);
+            }
+        }
+
+        function divide(n) {
+            var i = size, c = 0;
+            while (--i >= 0) {
+                c += data[i];
+                data[i] = Math.floor(c / n);
+                c = (c % n) * base;
+            }
+        }
+
+        function toString() {
+            var i = size;
+            var s = '';
+            while (--i >= 0) {
+                if (s !== '' || i === 0 || data[i] !== 0) {
+                    var t = String(data[i]);
+                    if (s === '') {
+                        s = t;
+                    } else {
+                        s += '0000000'.slice(0, 7 - t.length) + t;
+                    }
+                }
+            }
+            return s;
+        }
+
+        function pow(x, n, acc) {
+            return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x)
+                : pow(x * x, n / 2, acc)));
+        }
+
+        function log(x) {
+            var n = 0;
+            while (x >= 4096) {
+                n += 12;
+                x /= 4096;
+            }
+            while (x >= 2) {
+                n += 1;
+                x /= 2;
+            }
+            return n;
+        }
+
+        Number.prototype.toFixed = function (fractionDigits) {
+            var f, x, s, m, e, z, j, k;
+            f = Number(fractionDigits);
+            f = f !== f ? 0 : Math.floor(f);
+
+            if (f < 0 || f > 20) {
+                throw new RangeError('Number.toFixed called with invalid number of decimals');
+            }
+
+            x = Number(this);
+
+            if (x !== x) {
+                return "NaN";
+            }
+
+            if (x <= -1e21 || x > 1e21) {
+                return String(x);
+            }
+
+            s = "";
+
+            if (x < 0) {
+                s = "-";
+                x = -x;
+            }
+
+            m = "0";
+
+            if (x > 1e-21) {
+                //1e-21<x<1e21
+                //-70<log2(x)<70
+                e = log(x * pow(2, 69, 1)) - 69;
+                z = (e < 0 ? x * pow(2, -e, 1) : x / pow(2, e, 1));
+                z *= 0x10000000000000;//Math.pow(2,52);
+                e = 52 - e;
+
+                //-18<e<122
+                //x=z/2^e
+                if (e > 0) {
+                    multiply(0, z);
+                    j = f;
+
+                    while (j >= 7) {
+                        multiply(1e7, 0);
+                        j -= 7;
+                    }
+
+                    multiply(pow(10, j, 1), 0);
+                    j = e - 1;
+
+                    while (j >= 23) {
+                        divide(1 << 23);
+                        j -= 23;
+                    }
+                    divide(1 << j);
+                    multiply(1, 1);
+                    divide(2);
+                    m = toString();
+                } else {
+                    multiply(0, z);
+                    multiply(1 << (-e), 0);
+                    m = toString() + '0.00000000000000000000'.slice(2, 2 + f);
+                }
+            }
+
+            if (f > 0) {
+                k = m.length;
+
+                if (k <= f) {
+                    m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
+                } else {
+                    m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
+                }
+            } else {
+                m = s + m;
+            }
+
+            return m;
+        }
+
+    })();
+}
+
+
+/**
+ ** 加法函数,用来得到精确的加法结果
+ ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
+ ** 调用:accAdd(arg1,arg2)
+ ** 返回值:arg1加上arg2的精确结果
+ **/
+function accAdd(arg1, arg2) {
+    var r1, r2, m, c;
+    try {
+        r1 = arg1.toString().split(".")[1].length;
+    }
+    catch (e) {
+        r1 = 0;
+    }
+    try {
+        r2 = arg2.toString().split(".")[1].length;
+    }
+    catch (e) {
+        r2 = 0;
+    }
+    c = Math.abs(r1 - r2);
+    m = Math.pow(10, Math.max(r1, r2));
+    if (c > 0) {
+        var cm = Math.pow(10, c);
+        if (r1 > r2) {
+            arg1 = Number(arg1.toString().replace(".", ""));
+            arg2 = Number(arg2.toString().replace(".", "")) * cm;
+        } else {
+            arg1 = Number(arg1.toString().replace(".", "")) * cm;
+            arg2 = Number(arg2.toString().replace(".", ""));
+        }
+    } else {
+        arg1 = Number(arg1.toString().replace(".", ""));
+        arg2 = Number(arg2.toString().replace(".", ""));
+    }
+    return (arg1 + arg2) / m;
+}
+
+//给Number类型增加一个add方法,调用起来更加方便。
+Number.prototype.add = function (arg) {
+    return accAdd(arg, this);
+};
+/**
+ ** 减法函数,用来得到精确的减法结果
+ ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
+ ** 调用:accSub(arg1,arg2)
+ ** 返回值:arg1加上arg2的精确结果
+ **/
+function accSub(arg1, arg2) {
+    var r1, r2, m, n;
+    try {
+        r1 = arg1.toString().split(".")[1].length;
+    }
+    catch (e) {
+        r1 = 0;
+    }
+    try {
+        r2 = arg2.toString().split(".")[1].length;
+    }
+    catch (e) {
+        r2 = 0;
+    }
+    m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
+    n = (r1 >= r2) ? r1 : r2;
+    return ((arg1 * m - arg2 * m) / m).toFixed(n);
+}
+
+// 给Number类型增加一个mul方法,调用起来更加方便。
+Number.prototype.sub = function (arg) {
+    return accSub(this, arg);
+};
+/**
+ ** 乘法函数,用来得到精确的乘法结果
+ ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
+ ** 调用:accMul(arg1,arg2)
+ ** 返回值:arg1乘以 arg2的精确结果
+ **/
+function accMul(arg1, arg2) {
+    var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
+    try {
+        m += s1.split(".")[1].length;
+    }
+    catch (e) {
+    }
+    try {
+        m += s2.split(".")[1].length;
+    }
+    catch (e) {
+    }
+    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
+}
+
+// 给Number类型增加一个mul方法,调用起来更加方便。
+Number.prototype.mul = function (arg) {
+    return accMul(arg, this);
+};
+/**
+ ** 除法函数,用来得到精确的除法结果
+ ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
+ ** 调用:accDiv(arg1,arg2)
+ ** 返回值:arg1除以arg2的精确结果
+ **/
+function accDiv(arg1, arg2) {
+    var t1 = 0, t2 = 0, r1, r2;
+    try {
+        t1 = arg1.toString().split(".")[1].length;
+    }
+    catch (e) {
+    }
+    try {
+        t2 = arg2.toString().split(".")[1].length;
+    }
+    catch (e) {
+    }
+    with (Math) {
+        r1 = Number(arg1.toString().replace(".", ""));
+        r2 = Number(arg2.toString().replace(".", ""));
+        return (r1 / r2) * pow(10, t2 - t1);
+    }
+}
+
+//给Number类型增加一个div方法,调用起来更加方便。
+Number.prototype.div = function (arg) {
+    return accDiv(this, arg);
+};/**
+ * 特殊情况
+ * Created by wang on 15/6/23.
+ */
+//解决console未定义问题 guy
+window.console = window.console || (function () {
+        var c = {};
+        c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile
+            = c.clear = c.exception = c.trace = c.assert = function () {
+        };
+        return c;
+    })();
+
+
+//修复ie9下sort方法的bug
+!function (window) {
+    var ua = window.navigator.userAgent.toLowerCase(),
+        reg = /msie|applewebkit.+safari/;
+    if (reg.test(ua)) {
+        var _sort = Array.prototype.sort;
+        Array.prototype.sort = function (fn) {
+            if (!!fn && typeof fn === 'function') {
+                if (this.length < 2) {
+                    return this;
+                }
+                var i = 0, j = i + 1, l = this.length, tmp, r = false, t = 0;
+                for (; i < l; i++) {
+                    for (j = i + 1; j < l; j++) {
+                        t = fn.call(this, this[i], this[j]);
+                        r = (typeof t === 'number' ? t :
+                                !!t ? 1 : 0) > 0;
+                        if (r === true) {
+                            tmp = this[i];
+                            this[i] = this[j];
+                            this[j] = tmp;
+                        }
+                    }
+                }
+                return this;
+            } else {
+                return _sort.call(this);
+            }
+        };
+    }
+}(window);/**
+ * 对字符串对象的扩展
+ * @class String
+ */
+$.extend(String.prototype, {
+
+    /**
+     * 判断字符串是否已指定的字符串开始
+     * @param {String} startTag   指定的开始字符串
+     * @return {Boolean}  如果字符串以指定字符串开始则返回true,否则返回false
+     */
+    startWith: function (startTag) {
+        if (startTag == null || startTag == "" || this.length === 0 || startTag.length > this.length) {
+            return false;
+        }
+        return this.substr(0, startTag.length) == startTag;
+    },
+    /**
+     * 判断字符串是否以指定的字符串结束
+     * @param {String} endTag 指定的字符串
+     * @return {Boolean}  如果字符串以指定字符串结束则返回true,否则返回false
+     */
+    endWith: function (endTag) {
+        if (endTag == null || endTag == "" || this.length === 0 || endTag.length > this.length) {
+            return false;
+        }
+        return this.substring(this.length - endTag.length) == endTag;
+    },
+
+    /**
+     * 获取url中指定名字的参数
+     * @param {String} name 参数的名字
+     * @return {String} 参数的值
+     */
+    getQuery: function (name) {
+        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
+        var r = this.substr(this.indexOf("?") + 1).match(reg);
+        if (r) {
+            return unescape(r[2]);
+        }
+        return null;
+    },
+
+    /**
+     * 给url加上给定的参数
+     * @param {Object} paras 参数对象,是一个键值对对象
+     * @return {String} 添加了给定参数的url
+     */
+    appendQuery: function (paras) {
+        if (!paras) {
+            return this;
+        }
+        var src = this;
+        // 没有问号说明还没有参数
+        if (src.indexOf("?") === -1) {
+            src += "?";
+        }
+        // 如果以问号结尾,说明没有其他参数
+        if (src.endWith("?") !== false) {
+        } else {
+            src += "&";
+        }
+        $.each(paras, function (name, value) {
+            if (typeof(name) === 'string') {
+                src += name + "=" + value + "&";
+            }
+        });
+        src = src.substr(0, src.length - 1);
+        return src;
+    },
+    /**
+     * 将所有符合第一个字符串所表示的字符串替换成为第二个字符串
+     * @param {String} s1 要替换的字符串的正则表达式
+     * @param {String} s2 替换的结果字符串
+     * @returns {String} 替换后的字符串
+     */
+    replaceAll: function (s1, s2) {
+        return this.replace(new RegExp(s1, "gm"), s2);
+    },
+    /**
+     * 总是让字符串以指定的字符开头
+     * @param {String} start 指定的字符
+     * @returns {String} 以指定字符开头的字符串
+     */
+    perfectStart: function (start) {
+        if (this.startWith(start)) {
+            return this;
+        } else {
+            return start + this;
+        }
+    },
+
+    /**
+     * 获取字符串中某字符串的所有项位置数组
+     * @param {String} sub 子字符串
+     * @return {Number[]} 子字符串在父字符串中出现的所有位置组成的数组
+     */
+    allIndexOf: function (sub) {
+        if (typeof sub != 'string') {
+            return [];
+        }
+        var str = this;
+        var location = [];
+        var offset = 0;
+        while (str.length > 0) {
+            var loc = str.indexOf(sub);
+            if (loc === -1) {
+                break;
+            }
+            location.push(offset + loc);
+            str = str.substring(loc + sub.length, str.length);
+            offset += loc + sub.length;
+        }
+        return location;
+    }
+});
+
+/**
+ * 对字符串对象的扩展
+ * @class String
+ */
+$.extend(String, {
+
+    /**
+     * 对字符串中的'和\做编码处理
+     * @static
+     * @param {String} string 要做编码处理的字符串
+     * @return {String} 编码后的字符串
+     */
+    escape: function (string) {
+        return string.replace(/('|\\)/g, "\\$1");
+    },
+
+    /**
+     * 让字符串通过指定字符做补齐的函数
+     *
+     *      var s = String.leftPad('123', 5, '0');//s的值为:'00123'
+     *
+     * @static
+     * @param {String} val 原始值
+     * @param {Number} size 总共需要的位数
+     * @param {String} ch 用于补齐的字符
+     * @return {String}  补齐后的字符串
+     */
+    leftPad: function (val, size, ch) {
+        var result = String(val);
+        if (!ch) {
+            ch = " ";
+        }
+        while (result.length < size) {
+            result = ch + result;
+        }
+        return result.toString();
+    },
+
+    /**
+     * 对字符串做替换的函数
+     *
+     *      var cls = 'my-class', text = 'Some text';
+     *      var res = String.format('<div class="{0}>{1}</div>"', cls, text);
+     *      //res的值为:'<div class="my-class">Some text</div>';
+     *
+     * @static
+     * @param {String} format 要做替换的字符串,替换字符串1,替换字符串2...
+     * @return {String} 做了替换后的字符串
+     */
+    format: function (format) {
+        var args = Array.prototype.slice.call(arguments, 1);
+        return format.replace(/\{(\d+)\}/g, function (m, i) {
+            return args[i];
+        });
+    }
+});/**
+ * guy
+ * 状态常量
+ */
+
+_.extend(BI, {
+    Status: {
+        SUCCESS: 1,
+        WRONG: 2,
+        START: 3,
+        END: 4,
+        WAITING: 5,
+        READY: 6,
+        RUNNING: 7,
+        OUTOFBOUNDS: 8,
+        NULL: -1
+    },
+    Direction: {
+        Top: "top",
+        Bottom: "bottom",
+        Left: "left",
+        Right: "right",
+        Custom: "custom"
+    },
+    Axis: {
+        Vertical: "vertical",
+        Horizontal: "horizontal"
+    },
+    Selection: {
+        Default: -999,
+        None: -1,
+        Single: 0,
+        Multi: 1,
+        All: 2
+    },
+    HorizontalAlign: {
+        Left: "left",
+        Right: "right",
+        Center: "center"
+    },
+    VerticalAlign: {
+        Middle: "middle",
+        Top: "top",
+        Bottom: "bottom"
+    }
+});BI.EventListener = {
+    listen: function listen(target, eventType, callback) {
+        if (target.addEventListener) {
+            target.addEventListener(eventType, callback, false);
+            return {
+                remove: function remove() {
+                    target.removeEventListener(eventType, callback, false);
+                }
+            };
+        } else if (target.attachEvent) {
+            target.attachEvent('on' + eventType, callback);
+            return {
+                remove: function remove() {
+                    target.detachEvent('on' + eventType, callback);
+                }
+            };
+        }
+    },
+
+    capture: function capture(target, eventType, callback) {
+        if (target.addEventListener) {
+            target.addEventListener(eventType, callback, true);
+            return {
+                remove: function remove() {
+                    target.removeEventListener(eventType, callback, true);
+                }
+            };
+        } else {
+            return {
+                remove: BI.emptyFn
+            };
+        }
+    },
+
+    registerDefault: function registerDefault() {
+    }
+};!(function () {
+    var cancelAnimationFrame =
+        window.cancelAnimationFrame ||
+        window.webkitCancelAnimationFrame ||
+        window.mozCancelAnimationFrame ||
+        window.oCancelAnimationFrame ||
+        window.msCancelAnimationFrame ||
+        window.clearTimeout;
+
+    var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout;
+
+
+    BI.MouseMoveTracker = function (onMove, onMoveEnd, domNode) {
+        this._isDragging = false;
+        this._animationFrameID = null;
+        this._domNode = domNode;
+        this._onMove = onMove;
+        this._onMoveEnd = onMoveEnd;
+
+        this._onMouseMove = BI.bind(this._onMouseMove, this);
+        this._onMouseUp = BI.bind(this._onMouseUp, this);
+        this._didMouseMove = BI.bind(this._didMouseMove, this);
+    };
+    BI.MouseMoveTracker.prototype = {
+        constructor: BI.MouseMoveTracker,
+        captureMouseMoves: function (/*object*/ event) {
+            if (!this._eventMoveToken && !this._eventUpToken) {
+                this._eventMoveToken = BI.EventListener.listen(
+                    this._domNode,
+                    'mousemove',
+                    this._onMouseMove
+                );
+                this._eventUpToken = BI.EventListener.listen(
+                    this._domNode,
+                    'mouseup',
+                    this._onMouseUp
+                );
+            }
+
+            if (!this._isDragging) {
+                this._deltaX = 0;
+                this._deltaY = 0;
+                this._isDragging = true;
+                this._x = event.clientX;
+                this._y = event.clientY;
+            }
+            event.preventDefault ? event.preventDefault() : (event.returnValue = false);
+        },
+
+        releaseMouseMoves: function () {
+            if (this._eventMoveToken && this._eventUpToken) {
+                this._eventMoveToken.remove();
+                this._eventMoveToken = null;
+                this._eventUpToken.remove();
+                this._eventUpToken = null;
+            }
+
+            if (this._animationFrameID !== null) {
+                cancelAnimationFrame(this._animationFrameID);
+                this._animationFrameID = null;
+            }
+
+            if (this._isDragging) {
+                this._isDragging = false;
+                this._x = null;
+                this._y = null;
+            }
+        },
+
+        isDragging: function () /*boolean*/ {
+            return this._isDragging;
+        },
+
+        _onMouseMove: function (/*object*/ event) {
+            var x = event.clientX;
+            var y = event.clientY;
+
+            this._deltaX += (x - this._x);
+            this._deltaY += (y - this._y);
+
+            if (this._animationFrameID === null) {
+                // The mouse may move faster then the animation frame does.
+                // Use `requestAnimationFrame` to avoid over-updating.
+                this._animationFrameID =
+                    requestAnimationFrame(this._didMouseMove);
+            }
+
+            this._x = x;
+            this._y = y;
+            event.preventDefault ? event.preventDefault() : (event.returnValue = false);
+        },
+
+        _didMouseMove: function () {
+            this._animationFrameID = null;
+            this._onMove(this._deltaX, this._deltaY);
+            this._deltaX = 0;
+            this._deltaY = 0;
+        },
+
+        _onMouseUp: function () {
+            if (this._animationFrameID) {
+                this._didMouseMove();
+            }
+            this._onMoveEnd();
+        }
+    };
+})();!(function () {
+    var PIXEL_STEP = 10;
+    var LINE_HEIGHT = 40;
+    var PAGE_HEIGHT = 800;
+    var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout;
+
+    function normalizeWheel(/*object*/event) /*object*/ {
+        var sX = 0,
+            sY = 0,
+            // spinX, spinY
+            pX = 0,
+            pY = 0; // pixelX, pixelY
+
+        // Legacy
+        if ('detail' in event) {
+            sY = event.detail;
+        }
+        if ('wheelDelta' in event) {
+            sY = -event.wheelDelta / 120;
+        }
+        if ('wheelDeltaY' in event) {
+            sY = -event.wheelDeltaY / 120;
+        }
+        if ('wheelDeltaX' in event) {
+            sX = -event.wheelDeltaX / 120;
+        }
+
+        // side scrolling on FF with DOMMouseScroll
+        if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
+            sX = sY;
+            sY = 0;
+        }
+
+        pX = sX * PIXEL_STEP;
+        pY = sY * PIXEL_STEP;
+
+        if ('deltaY' in event) {
+            pY = event.deltaY;
+        }
+        if ('deltaX' in event) {
+            pX = event.deltaX;
+        }
+
+        if ((pX || pY) && event.deltaMode) {
+            if (event.deltaMode === 1) {
+                // delta in LINE units
+                pX *= LINE_HEIGHT;
+                pY *= LINE_HEIGHT;
+            } else {
+                // delta in PAGE units
+                pX *= PAGE_HEIGHT;
+                pY *= PAGE_HEIGHT;
+            }
+        }
+
+        // Fall-back if spin cannot be determined
+        if (pX && !sX) {
+            sX = pX < 1 ? -1 : 1;
+        }
+        if (pY && !sY) {
+            sY = pY < 1 ? -1 : 1;
+        }
+
+        return {
+            spinX: sX,
+            spinY: sY,
+            pixelX: pX,
+            pixelY: pY
+        };
+    }
+
+    BI.WheelHandler = function (onWheel, handleScrollX, handleScrollY, stopPropagation) {
+        this._animationFrameID = null;
+        this._deltaX = 0;
+        this._deltaY = 0;
+        this._didWheel = BI.bind(this._didWheel, this);
+        if (typeof handleScrollX !== 'function') {
+            handleScrollX = handleScrollX ?
+                function () {
+                    return true
+                } :
+                function () {
+                    return false
+                };
+        }
+
+        if (typeof handleScrollY !== 'function') {
+            handleScrollY = handleScrollY ?
+                function () {
+                    return true
+                } :
+                function () {
+                    return false
+                };
+        }
+
+        if (typeof stopPropagation !== 'function') {
+            stopPropagation = stopPropagation ?
+                function () {
+                    return true
+                } :
+                function () {
+                    return false
+                };
+        }
+
+        this._handleScrollX = handleScrollX;
+        this._handleScrollY = handleScrollY;
+        this._stopPropagation = stopPropagation;
+        this._onWheelCallback = onWheel;
+        this.onWheel = BI.bind(this.onWheel, this);
+    };
+    BI.WheelHandler.prototype = {
+        constructor: BI.WheelHandler,
+        onWheel: function (/*object*/ event) {
+            var normalizedEvent = normalizeWheel(event);
+            var deltaX = this._deltaX + normalizedEvent.pixelX;
+            var deltaY = this._deltaY + normalizedEvent.pixelY;
+            var handleScrollX = this._handleScrollX(deltaX, deltaY);
+            var handleScrollY = this._handleScrollY(deltaY, deltaX);
+            if (!handleScrollX && !handleScrollY) {
+                return;
+            }
+
+            this._deltaX += handleScrollX ? normalizedEvent.pixelX : 0;
+            this._deltaY += handleScrollY ? normalizedEvent.pixelY : 0;
+            event.preventDefault ? event.preventDefault() : (event.returnValue = false);
+
+            var changed;
+            if (this._deltaX !== 0 || this._deltaY !== 0) {
+                if (this._stopPropagation()) {
+                    event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);
+                }
+                changed = true;
+            }
+
+            if (changed === true && this._animationFrameID === null) {
+                this._animationFrameID = requestAnimationFrame(this._didWheel);
+            }
+        },
+
+        _didWheel: function () {
+            this._animationFrameID = null;
+            this._onWheelCallback(this._deltaX, this._deltaY);
+            this._deltaX = 0;
+            this._deltaY = 0;
+        }
+    };
+})();/**
+ * 常量
+ */
+
+_.extend(BI, {
+    MAX: 0xfffffffffffffff,
+    MIN: -0xfffffffffffffff,
+    EVENT_RESPONSE_TIME: 200,
+    zIndex_layer: 1e5,
+    zIndex_floatbox: 1e6,
+    zIndex_popup: 1e7,
+    zIndex_masker: 1e8,
+    zIndex_tip: 1e9,
+    emptyStr: "",
+    emptyFn: function () {
+    },
+    empty: null
+});/**
+ * absolute实现的居中布局
+ * @class BI.AbsoluteCenterLayout
+ * @extends BI.Layout
+ */
+BI.AbsoluteCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.AbsoluteCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-absolute-center-layout",
+            hgap: 0,
+            lgap: 0,
+            rgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    created: function () {
+        BI.AbsoluteCenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.AbsoluteCenterLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "absolute",
+            "left": o.hgap + o.lgap + (item.lgap || 0),
+            "right": o.hgap + o.rgap + (item.rgap || 0),
+            "top": o.vgap + o.tgap + (item.tgap || 0),
+            "bottom": o.vgap + o.bgap + (item.bgap || 0),
+            "margin": "auto"
+        });
+        return w;
+    },
+
+    resize: function () {
+        // console.log("absolute_center_adapt布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.AbsoluteCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.absolute_center_adapt', BI.AbsoluteCenterLayout);/**
+ * absolute实现的居中布局
+ * @class BI.AbsoluteHorizontalLayout
+ * @extends BI.Layout
+ */
+BI.AbsoluteHorizontalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.AbsoluteHorizontalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-absolute-horizontal-layout",
+            hgap: 0,
+            lgap: 0,
+            rgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    created: function () {
+        BI.AbsoluteHorizontalLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.AbsoluteHorizontalLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "absolute",
+            "left": o.hgap + o.lgap + (item.lgap || 0),
+            "right": o.hgap + o.rgap + (item.rgap || 0),
+            "margin": "auto"
+        });
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css("top", o.vgap + o.tgap + (item.tgap || 0));
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css("bottom", o.vgap + o.bgap + (item.bgap || 0));
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("absolute_horizontal_adapt布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.AbsoluteHorizontalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.absolute_horizontal_adapt', BI.AbsoluteHorizontalLayout);/**
+ * absolute实现的居中布局
+ * @class BI.AbsoluteVerticalLayout
+ * @extends BI.Layout
+ */
+BI.AbsoluteVerticalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.AbsoluteVerticalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-absolute-vertical-layout",
+            hgap: 0,
+            lgap: 0,
+            rgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    created: function () {
+        BI.AbsoluteVerticalLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.AbsoluteVerticalLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "absolute",
+            "left": item.lgap,
+            "right": item.rgap,
+            "top": o.vgap + o.tgap + (item.tgap || 0),
+            "bottom": o.vgap + o.bgap + (item.bgap || 0),
+            "margin": "auto"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css("left", o.hgap + o.lgap + (item.lgap || 0));
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css("right", o.hgap + o.rgap + (item.rgap || 0));
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("absolute_vertical_adapt布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.AbsoluteVerticalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.absolute_vertical_adapt', BI.AbsoluteVerticalLayout);/**
+ * 自适应水平和垂直方向都居中容器
+ * @class BI.CenterAdaptLayout
+ * @extends BI.Layout
+ */
+BI.CenterAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.CenterAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-center-adapt-layout",
+            columnSize: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.CenterAdaptLayout.superclass.created.apply(this, arguments);
+        this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({
+            "position": "relative",
+            "width": "100%",
+            "height": "100%",
+            "white-space": "nowrap",
+            "border-spacing": "0px",
+            "border": "none",
+            "border-collapse": "separate"
+        });
+        this.$tr = $("<tr>");
+        this.$tr.appendTo(this.$table);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var td;
+        var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i];
+        if (!this.hasWidget(this.getName() + "-" + i)) {
+            var w = BI.createWidget(item);
+            w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"});
+            td = BI.createWidget({
+                type: "bi.default",
+                tagName: "td",
+                attributes: {
+                    width: width
+                },
+                items: [w]
+            });
+            this.addWidget(this.getName() + "-" + i, td);
+        } else {
+            td = this.getWidgetByName(this.getName() + "-" + i);
+            td.element.attr("width", width);
+        }
+        td.element.css({"max-width": o.columnSize[i]});
+        if (i === 0) {
+            td.element.addClass("first-element");
+        }
+        td.element.css({
+            "position": "relative",
+            "height": "100%",
+            "vertical-align": "middle",
+            "margin": "0",
+            "padding": "0",
+            "border": "none"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return td;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$tr.append(frag);
+            this.element.append(this.$table);
+        }
+    },
+
+    resize: function () {
+        // console.log("center_adapt布局不需要resize");
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$tr);
+        return w;
+    },
+
+    populate: function (items) {
+        BI.CenterAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.center_adapt', BI.CenterAdaptLayout);/**
+ * 水平方向居中容器
+ * @class BI.HorizontalAdaptLayout
+ * @extends BI.Layout
+ */
+BI.HorizontalAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HorizontalAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-horizontal-adapt-layout",
+            verticalAlign: BI.VerticalAlign.Middle,
+            columnSize: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.HorizontalAdaptLayout.superclass.created.apply(this, arguments);
+        this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({
+            "position": "relative",
+            "width": "100%",
+            "white-space": "nowrap",
+            "border-spacing": "0px",
+            "border": "none",
+            "border-collapse": "separate"
+        });
+        this.$tr = $("<tr>");
+        this.$tr.appendTo(this.$table);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var td;
+        var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i];
+        if (!this.hasWidget(this.getName() + "-" + i)) {
+            var w = BI.createWidget(item);
+            w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"});
+            td = BI.createWidget({
+                type: "bi.default",
+                tagName: "td",
+                attributes: {
+                    width: width
+                },
+                items: [w]
+            });
+            this.addWidget(this.getName() + "-" + i, td);
+        } else {
+            td = this.getWidgetByName(this.getName() + "-" + i);
+            td.element.attr("width", width);
+        }
+        td.element.css({"max-width": o.columnSize[i] + "px"});
+        if (i === 0) {
+            td.element.addClass("first-element");
+        }
+        td.element.css({
+            "position": "relative",
+            "vertical-align": o.verticalAlign,
+            "margin": "0",
+            "padding": "0",
+            "border": "none"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return td;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$tr.append(frag);
+            this.element.append(this.$table);
+        }
+    },
+
+    resize: function () {
+        // console.log("horizontal_adapt布局不需要resize");
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$tr);
+        return w;
+    },
+
+    populate: function (items) {
+        BI.HorizontalAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal_adapt', BI.HorizontalAdaptLayout);/**
+ * 左右分离,垂直方向居中容器
+ *          items:{
+                left: [{el:{type:"bi.button"}}],
+                right:[{el:{type:"bi.button"}}]
+            }
+ * @class BI.LeftRightVerticalAdaptLayout
+ * @extends BI.Layout
+ */
+BI.LeftRightVerticalAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.LeftRightVerticalAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-left-right-vertical-adapt-layout",
+            items: {},
+            llgap: 0,
+            lrgap: 0,
+            lhgap: 0,
+            rlgap: 0,
+            rrgap: 0,
+            rhgap: 0
+        });
+    },
+    created: function () {
+        BI.LeftRightVerticalAdaptLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("left_right_vertical_adapt布局不需要resize");
+    },
+
+    addItem: function () {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var o = this.options;
+        if ("left" in items) {
+            var left = BI.createWidget({
+                type: "bi.vertical_adapt",
+                items: items.left,
+                hgap: o.lhgap,
+                lgap: o.llgap,
+                rgap: o.lrgap
+            });
+            left.element.css("height", "100%");
+            BI.createWidget({
+                type: "bi.left",
+                element: this,
+                items: [left]
+            });
+        }
+        if ("right" in items) {
+            var right = BI.createWidget({
+                type: "bi.vertical_adapt",
+                items: items.right,
+                hgap: o.rhgap,
+                lgap: o.rlgap,
+                rgap: o.rrgap
+            });
+            right.element.css("height", "100%");
+            BI.createWidget({
+                type: "bi.right",
+                element: this,
+                items: [right]
+            });
+        }
+    },
+
+    populate: function (items) {
+        BI.LeftRightVerticalAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.left_right_vertical_adapt', BI.LeftRightVerticalAdaptLayout);
+
+
+BI.LeftVerticalAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.LeftRightVerticalAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-left-vertical-adapt-layout",
+            items: [],
+            lgap: 0,
+            rgap: 0,
+            hgap: 0
+        });
+    },
+    created: function () {
+        BI.LeftVerticalAdaptLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        console.log("left_vertical_adapt布局不需要resize");
+    },
+
+    addItem: function () {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    populate: function (items) {
+        BI.LeftVerticalAdaptLayout.superclass.populate.apply(this, arguments);
+        var o = this.options;
+        var left = BI.createWidget({
+            type: "bi.vertical_adapt",
+            items: items,
+            lgap: o.lgap,
+            hgap: o.hgap,
+            rgap: o.rgap
+        });
+        left.element.css("height", "100%");
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [left]
+        });
+        this._mount();
+    }
+});
+$.shortcut('bi.left_vertical_adapt', BI.LeftVerticalAdaptLayout);
+
+BI.RightVerticalAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.RightVerticalAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-right-vertical-adapt-layout",
+            items: [],
+            lgap: 0,
+            rgap: 0,
+            hgap: 0
+        });
+    },
+    created: function () {
+        BI.RightVerticalAdaptLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        console.log("right_vertical_adapt布局不需要resize");
+    },
+
+    addItem: function () {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    populate: function (items) {
+        BI.RightVerticalAdaptLayout.superclass.populate.apply(this, arguments);
+        var o = this.options;
+        var right = BI.createWidget({
+            type: "bi.vertical_adapt",
+            items: items,
+            lgap: o.lgap,
+            hgap: o.hgap,
+            rgap: o.rgap
+        });
+        right.element.css("height", "100%");
+        BI.createWidget({
+            type: "bi.right",
+            element: this,
+            items: [right]
+        });
+        this._mount();
+    }
+});
+$.shortcut('bi.right_vertical_adapt', BI.RightVerticalAdaptLayout);/**
+ * 垂直方向居中容器
+ * @class BI.VerticalAdaptLayout
+ * @extends BI.Layout
+ */
+BI.VerticalAdaptLayout = BI.inherit(BI.Layout, {
+    _defaultConfig: function () {
+        return BI.extend(BI.VerticalAdaptLayout.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-vertical-adapt-layout",
+            columnSize: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    _init: function () {
+        BI.VerticalAdaptLayout.superclass._init.apply(this, arguments);
+        this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({
+            "position": "relative",
+            "height": "100%",
+            "white-space": "nowrap",
+            "border-spacing": "0px",
+            "border": "none",
+            "border-collapse": "separate"
+        });
+        this.$tr = $("<tr>");
+        this.$tr.appendTo(this.$table);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var td;
+        var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i];
+        if (!this.hasWidget(this.getName() + "-" + i)) {
+            var w = BI.createWidget(item);
+            w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"});
+            td = BI.createWidget({
+                type: "bi.default",
+                tagName: "td",
+                attributes: {
+                    width: width
+                },
+                items: [w]
+            });
+            this.addWidget(this.getName() + "-" + i, td);
+        } else {
+            td = this.getWidgetByName(this.getName() + "-" + i);
+            td.element.attr("width", width);
+        }
+
+        if (i === 0) {
+            td.element.addClass("first-element");
+        }
+        td.element.css({
+            "position": "relative",
+            "height": "100%",
+            "vertical-align": "middle",
+            "margin": "0",
+            "padding": "0",
+            "border": "none"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return td;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$tr.append(frag);
+            this.element.append(this.$table);
+        }
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$tr);
+        return w;
+    },
+
+    resize: function () {
+        // console.log("vertical_adapt布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.VerticalAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.vertical_adapt', BI.VerticalAdaptLayout);/**
+ * 水平方向居中自适应容器
+ * @class BI.HorizontalAutoLayout
+ * @extends BI.Layout
+ */
+BI.HorizontalAutoLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HorizontalAutoLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-horizon-auto-layout",
+            hgap: 0,
+            lgap: 0,
+            rgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    created: function () {
+        BI.HorizontalAutoLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.HorizontalAutoLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "relative",
+            "margin": "0px auto"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("horizontal_adapt布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.HorizontalAutoLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal_auto', BI.HorizontalAutoLayout);/**
+ * 浮动的居中布局
+ */
+BI.FloatCenterAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FloatCenterAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-float-center-adapt-layout",
+            items: [],
+            hgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0,
+            lgap: 0,
+            rgap: 0
+        });
+    },
+    created: function () {
+        BI.FloatCenterAdaptLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("float_center_adapt布局不需要resize");
+    },
+
+    addItem: function () {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    mounted: function () {
+        var width = this.left.element.width(),
+            height = this.left.element.height();
+        this.left.element.width(width).height(height).css("float", "none");
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            items: [this.left]
+        });
+        this.removeWidget(this.container.getName());
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        this.left = BI.createWidget({
+            type: "bi.vertical",
+            items: items,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            lgap: o.lgap,
+            rgap: o.rgap
+        });
+
+        this.container = BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.left]
+        });
+
+    },
+
+    populate: function (items) {
+        BI.FloatCenterAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.float_center_adapt', BI.FloatCenterAdaptLayout);/**
+ * 浮动的水平居中布局
+ */
+BI.FloatHorizontalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FloatHorizontalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-float-horizontal-adapt-layout",
+            items: [],
+            hgap: 0,
+            vgap: 0,
+            tgap: 0,
+            bgap: 0,
+            lgap: 0,
+            rgap: 0
+        });
+    },
+    created: function () {
+        BI.FloatHorizontalLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("float_horizontal_adapt布局不需要resize");
+    },
+
+    mounted: function () {
+        var width = this.left.element.width(),
+            height = this.left.element.height();
+        this.left.element.width(width).height(height).css("float", "none");
+        BI.createWidget({
+            type: "bi.horizontal_auto",
+            element: this,
+            items: [this.left]
+        });
+        this.removeWidget(this.container.getName());
+    },
+
+    _addElement: function (i, item) {
+        var self = this, o = this.options;
+        this.left = BI.createWidget({
+            type: "bi.vertical",
+            items: items,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            lgap: o.lgap,
+            rgap: o.rgap
+        });
+
+        this.container = BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.left]
+        });
+
+        return left;
+    },
+
+    populate: function (items) {
+        BI.HorizontalAutoLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal_float', BI.FloatHorizontalLayout);/**
+ * 内联布局
+ * @class BI.InlineCenterAdaptLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.InlineCenterAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.InlineCenterAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-inline-center-adapt-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.InlineCenterAdaptLayout.superclass.created.apply(this, arguments);
+        this.element.css({
+            whiteSpace: "nowrap"
+        });
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item, length) {
+        var o = this.options;
+        if (!this.hasWidget(this.getName() + "-" + i)) {
+            var t = BI.createWidget(item);
+            t.element.css({
+                "position": "relative"
+            });
+            var w = BI.createWidget({
+                type: "bi.horizontal_auto",
+                items: [t]
+            });
+            this.addWidget(this.getName() + "-" + i, w);
+        } else {
+            var w = this.getWidgetByName(this.getName() + "-" + i);
+        }
+        w.element.css({
+            "position": "relative",
+            "display": "inline-block",
+            "vertical-align": "middle",
+            "*display": "inline",
+            "*zoom": 1,
+            "min-width": 100 / length + "%"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    addItem: function (item) {
+        throw new Error("不能添加元素");
+    },
+
+    stroke: function (items) {
+        var self = this;
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                self._addElement(i, item, items.length);
+            }
+        });
+    },
+
+    populate: function (items) {
+        BI.InlineCenterAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.inline_center_adapt', BI.InlineCenterAdaptLayout);/**
+ * 内联布局
+ * @class BI.InlineVerticalAdaptLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.InlineVerticalAdaptLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.InlineVerticalAdaptLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-inline-vertical-adapt-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.InlineVerticalAdaptLayout.superclass.created.apply(this, arguments);
+        this.element.css({
+            whiteSpace: "nowrap"
+        });
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.InlineVerticalAdaptLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "relative",
+            "display": "inline-block",
+            "vertical-align": "middle",
+            "*display": "inline",
+            "*zoom": 1
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.InlineVerticalAdaptLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.inline_vertical_adapt', BI.InlineVerticalAdaptLayout);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexCenterLayout
+ * @extends BI.Layout
+ */
+BI.FlexCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-center-layout"
+        });
+    },
+    created: function () {
+        BI.FlexCenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexCenterLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "flex-shrink": "0"});
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_center布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_center', BI.FlexCenterLayout);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexHorizontalLayout
+ * @extends BI.Layout
+ */
+BI.FlexHorizontalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexHorizontalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-horizontal-layout",
+            verticalAlign: "middle",
+            columnSize: [],
+            scrollx: true,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FlexHorizontalLayout.superclass.created.apply(this, arguments);
+        var o = this.options;
+        this.element.addClass(o.verticalAlign);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexHorizontalLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "flex-shrink": "0"});
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_horizontal布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexHorizontalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_horizontal', BI.FlexHorizontalLayout);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexVerticalCenter
+ * @extends BI.Layout
+ */
+BI.FlexVerticalCenter = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexVerticalCenter.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-vertical-center",
+            columnSize: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FlexVerticalCenter.superclass.created.apply(this, arguments);
+        var o = this.options;
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexVerticalCenter.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "flex-shrink": "0"});
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_vertical_center布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexVerticalCenter.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_vertical_center', BI.FlexVerticalCenter);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexCenterLayout
+ * @extends BI.Layout
+ */
+BI.FlexCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-wrapper-center-layout clearfix"
+        });
+    },
+    created: function () {
+        BI.FlexCenterLayout.superclass.created.apply(this, arguments);
+        this.$wrapper = $("<div>").addClass("flex-wrapper-center-layout-wrapper");
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexCenterLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative"});
+        return w;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$wrapper.append(frag);
+            this.element.append(this.$wrapper);
+        }
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$wrapper);
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_center布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_wrapper_center', BI.FlexCenterLayout);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexHorizontalLayout
+ * @extends BI.Layout
+ */
+BI.FlexHorizontalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexHorizontalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-wrapper-horizontal-layout clearfix",
+            verticalAlign: "middle",
+            columnSize: [],
+            scrollx: true,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FlexHorizontalLayout.superclass.created.apply(this, arguments);
+        var o = this.options;
+        this.$wrapper = $("<div>").addClass("flex-wrapper-horizontal-layout-wrapper " + o.verticalAlign);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexHorizontalLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative"});
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$wrapper.append(frag);
+            this.element.append(this.$wrapper);
+        }
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$wrapper);
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_horizontal布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexHorizontalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_wrapper_horizontal', BI.FlexHorizontalLayout);/**
+ *自适应水平和垂直方向都居中容器
+ * Created by GUY on 2016/12/2.
+ *
+ * @class BI.FlexVerticalCenter
+ * @extends BI.Layout
+ */
+BI.FlexVerticalCenter = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FlexVerticalCenter.superclass.props.apply(this, arguments), {
+            baseCls: "bi-flex-wrapper-vertical-center clearfix",
+            columnSize: [],
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FlexVerticalCenter.superclass.created.apply(this, arguments);
+        var o = this.options;
+        this.$wrapper = $("<div>").addClass("flex-wrapper-vertical-center-wrapper");
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FlexVerticalCenter.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative"});
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$wrapper.append(frag);
+            this.element.append(this.$wrapper);
+        }
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        this.options.items.push(item);
+        w.element.appendTo(this.$wrapper);
+        return w;
+    },
+
+    resize: function () {
+        // console.log("flex_vertical_center布局不需要resize");
+    },
+
+    populate: function (items) {
+        BI.FlexVerticalCenter.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.flex_wrapper_vertical_center', BI.FlexVerticalCenter);/**
+ * 固定子组件上下左右的布局容器
+ * @class BI.AbsoluteLayout
+ * @extends BI.Layout
+ */
+BI.AbsoluteLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.AbsoluteLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-absolute-layout",
+            hgap: null,
+            vgap: null,
+            lgap: null,
+            rgap: null,
+            tgap: null,
+            bgap: null
+        });
+    },
+    created: function () {
+        BI.AbsoluteLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.AbsoluteLayout.superclass._addElement.apply(this, arguments);
+        var left = 0, right = 0, top = 0, bottom = 0;
+        if (BI.isNotNull(item.left)) {
+            w.element.css({"left": item.left});
+            left += item.left;
+        }
+        if (BI.isNotNull(item.right)) {
+            w.element.css({"right": item.right});
+            right += item.right;
+        }
+        if (BI.isNotNull(item.top)) {
+            w.element.css({"top": item.top});
+            top += item.top;
+        }
+        if (BI.isNotNull(item.bottom)) {
+            w.element.css({"bottom": item.bottom});
+            bottom += item.bottom;
+        }
+
+        if (BI.isNotNull(o.hgap)) {
+            left += o.hgap;
+            w.element.css({"left": left});
+            right += o.hgap;
+            w.element.css({"right": right});
+        }
+        if (BI.isNotNull(o.vgap)) {
+            top += o.vgap;
+            w.element.css({"top": top});
+            bottom += o.vgap;
+            w.element.css({"bottom": bottom});
+        }
+
+        if (BI.isNotNull(o.lgap)) {
+            left += o.lgap;
+            w.element.css({"left": left});
+        }
+        if (BI.isNotNull(o.rgap)) {
+            right += o.rgap;
+            w.element.css({"right": right});
+        }
+        if (BI.isNotNull(o.tgap)) {
+            top += o.tgap;
+            w.element.css({"top": top});
+        }
+        if (BI.isNotNull(o.bgap)) {
+            bottom += o.bgap;
+            w.element.css({"bottom": bottom});
+        }
+
+
+        if (BI.isNotNull(item.width)) {
+            w.element.css({"width": item.width});
+        }
+        if (BI.isNotNull(item.height)) {
+            w.element.css({"height": item.height});
+        }
+        w.element.css({"position": "absolute"});
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    stroke: function (items) {
+        this.options.items = items || [];
+        var self = this;
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                if (!BI.isWidget(item) && !item.el) {
+                    throw new Error("absolute布局中el 是必要属性");
+                }
+                self._addElement(i, item);
+            }
+        });
+    },
+
+    populate: function (items) {
+        BI.AbsoluteLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.absolute', BI.AbsoluteLayout);BI.AdaptiveLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.AdaptiveLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-adaptive-layout",
+            hgap: null,
+            vgap: null,
+            lgap: null,
+            rgap: null,
+            tgap: null,
+            bgap: null
+        });
+    },
+    created: function () {
+        BI.AdaptiveLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.AdaptiveLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative"});
+        var left = 0, right = 0, top = 0, bottom = 0;
+        if (BI.isNotNull(item.left)) {
+            w.element.css({
+                "margin-left": item.left
+            })
+        }
+        if (BI.isNotNull(item.right)) {
+            w.element.css({
+                "margin-right": item.right
+            })
+        }
+        if (BI.isNotNull(item.top)) {
+            w.element.css({
+                "margin-top": item.top
+            })
+        }
+        if (BI.isNotNull(item.bottom)) {
+            w.element.css({
+                "margin-bottom": item.bottom
+            })
+        }
+
+        if (BI.isNotNull(o.hgap)) {
+            left += o.hgap;
+            w.element.css({"left": left});
+            right += o.hgap;
+            w.element.css({"right": right});
+        }
+        if (BI.isNotNull(o.vgap)) {
+            top += o.vgap;
+            w.element.css({"top": top});
+            bottom += o.vgap;
+            w.element.css({"bottom": bottom});
+        }
+
+        if (BI.isNotNull(o.lgap)) {
+            left += o.lgap;
+            w.element.css({"left": left});
+        }
+        if (BI.isNotNull(o.rgap)) {
+            right += o.rgap;
+            w.element.css({"right": right});
+        }
+        if (BI.isNotNull(o.tgap)) {
+            top += o.tgap;
+            w.element.css({"top": top});
+        }
+        if (BI.isNotNull(o.bgap)) {
+            bottom += o.bgap;
+            w.element.css({"bottom": bottom});
+        }
+
+        if (BI.isNotNull(item.width)) {
+            w.element.css({"width": item.width});
+        }
+        if (BI.isNotNull(item.height)) {
+            w.element.css({"height": item.height});
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.AbsoluteLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.adaptive', BI.AdaptiveLayout);/**
+ * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应
+ *
+ * @class BI.BorderLayout
+ * @extends BI.Layout
+ */
+BI.BorderLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.BorderLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-border-layout",
+            items: {}
+        });
+    },
+    created: function () {
+        BI.BorderLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    addItem: function (item) {
+        // do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function(regions){
+        var item;
+        var top = 0;
+        var bottom = 0;
+        var left = 0;
+        var right = 0;
+        if ("north" in regions) {
+            item = regions["north"];
+            if (item != null) {
+                if (item.el) {
+                    if (!this.hasWidget(this.getName() + "north")) {
+                        var w = BI.createWidget(item);
+                        this.addWidget(this.getName() + "north", w);
+                    }
+                    this.getWidgetByName(this.getName() + "north").element.height(item.height)
+                        .css({
+                            "position": "absolute",
+                            "top": (item.top || 0),
+                            "left": (item.left || 0),
+                            "right": (item.right || 0),
+                            "bottom": "initial"
+                        });
+                }
+                top = (item.height || 0) + (item.top || 0) + (item.bottom || 0);
+            }
+        }
+        if ("south" in regions) {
+            item = regions["south"];
+            if (item != null) {
+                if (item.el) {
+                    if (!this.hasWidget(this.getName() + "south")) {
+                        var w = BI.createWidget(item);
+                        this.addWidget(this.getName() + "south", w);
+                    }
+                    this.getWidgetByName(this.getName() + "south").element.height(item.height)
+                        .css({
+                            "position": "absolute",
+                            "bottom": (item.bottom || 0),
+                            "left": (item.left || 0),
+                            "right": (item.right || 0),
+                            "top": "initial"
+                        });
+                }
+                bottom = (item.height || 0) + (item.top || 0) + (item.bottom || 0);
+            }
+        }
+        if ("west" in regions) {
+            item = regions["west"];
+            if (item != null) {
+                if (item.el) {
+                    if (!this.hasWidget(this.getName() + "west")) {
+                        var w = BI.createWidget(item);
+                        this.addWidget(this.getName() + "west", w);
+                    }
+                    this.getWidgetByName(this.getName() + "west").element.width(item.width)
+                        .css({
+                            "position": "absolute",
+                            "left": (item.left || 0),
+                            top: top,
+                            bottom: bottom,
+                            "right": "initial"
+                        });
+                }
+                left = (item.width || 0) + (item.left || 0) + (item.right || 0);
+            }
+        }
+        if ("east" in regions) {
+            item = regions["east"];
+            if (item != null) {
+                if (item.el) {
+                    if (!this.hasWidget(this.getName() + "east")) {
+                        var w = BI.createWidget(item);
+                        this.addWidget(this.getName() + "east", w);
+                    }
+                    this.getWidgetByName(this.getName() + "east").element.width(item.width)
+                        .css({
+                            "position": "absolute",
+                            "right": (item.right || 0),
+                            top: top,
+                            bottom: bottom,
+                            "left": "initial"
+                        });
+                }
+                right = (item.width || 0) + (item.left || 0) + (item.right || 0);
+            }
+        }
+        if ("center" in regions) {
+            item = regions["center"];
+            if (item != null) {
+                if (!this.hasWidget(this.getName() + "center")) {
+                    var w = BI.createWidget(item);
+                    this.addWidget(this.getName() + "center", w);
+                }
+                this.getWidgetByName(this.getName() + "center").element
+                    .css({"position": "absolute", "top": top, "bottom": bottom, "left": left, "right": right});
+            }
+        }
+    },
+
+    populate: function (items) {
+        BI.BorderLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.border', BI.BorderLayout);/**
+ * 卡片布局,可以做到当前只显示一个组件,其他的都隐藏
+ * @class BI.CardLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {String} options.defaultShowName 默认展示的子组件名
+ */
+BI.CardLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.CardLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-card-layout",
+            items: []
+        });
+    },
+    created: function () {
+        BI.CardLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getCardName: function (cardName) {
+        return this.getName() + cardName;
+    },
+
+    resize: function () {
+        // console.log("default布局不需要resize");
+    },
+
+    stroke: function (items) {
+        var self = this;
+        this.showIndex = void 0;
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                if (!self.hasWidget(self._getCardName(item.cardName))) {
+                    var w = BI.createWidget(item);
+                    self.addWidget(self._getCardName(item.cardName), w);
+                } else {
+                    var w = self.getWidgetByName(self._getCardName(item.cardName));
+                }
+                w.element.css({"position": "absolute", "top": "0", "right": "0", "bottom": "0", "left": "0"});
+                w.setVisible(false);
+            }
+        });
+    },
+
+    populate: function (items) {
+        BI.CardLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+        this.options.defaultShowName && this.showCardByName(this.options.defaultShowName);
+    },
+
+    isCardExisted: function (cardName) {
+        return this.hasWidget(this._getCardName(cardName))
+            && $(this.getWidgetByName(this._getCardName(cardName)).element).length !== 0;
+    },
+
+    getCardByName: function (cardName) {
+        if (!this.hasWidget(this._getCardName(cardName))) {
+            throw new Error("cardName不存在,无法获取");
+        }
+        return this._children[this._getCardName(cardName)];
+    },
+
+    deleteCardByName: function (cardName) {
+        if (!this.hasWidget(this._getCardName(cardName))) {
+            throw new Error("cardName不存在,无法删除");
+        }
+        this.getWidgetByName(this._getCardName(cardName)).destroy();
+        var index = BI.findKey(this.options.items, function (i, item) {
+            return item.cardName == cardName;
+        });
+        this.options.items.splice(index, 1);
+        delete this._children[this._getCardName(cardName)];
+    },
+
+    addCardByName: function (cardName, cardItem) {
+        if (this.hasWidget(this._getCardName(cardName))) {
+            throw new Error("cardName已经存在了");
+        }
+        this.options.items.push({el: cardItem, cardName: cardName});
+        var widget = BI.createWidget(cardItem);
+        widget.element.css({"position": "relative", "top": "0", "left": "0", "width": "100%", "height": "100%"})
+            .appendTo(this.element);
+        widget.invisible();
+        this.addWidget(this._getCardName(cardName), widget);
+        return widget;
+    },
+
+    showCardByName: function (name, action, callback) {
+        var self = this;
+        //name不存在的时候全部隐藏
+        var exist = this.hasWidget(this._getCardName(name));
+        if (this.showIndex != null) {
+            this.lastShowIndex = this.showIndex;
+        }
+        this.showIndex = this._getCardName(name);
+        var flag = false;
+        BI.each(this._children, function (i, el) {
+            if (self._getCardName(name) != i) {
+                //动画效果只有在全部都隐藏的时候才有意义,且只要执行一次动画操作就够了
+                !flag && !exist && (BI.Action && action instanceof BI.Action) ? (action.actionBack(el), flag = true) : el.element.hide();
+            } else {
+                (BI.Action && action instanceof BI.Action) ? action.actionPerformed(void 0, el, callback) : el.element.show(0, callback);
+            }
+        });
+    },
+
+    showLastCard: function () {
+        var self = this;
+        this.showIndex = this.lastShowIndex;
+        BI.each(this._children, function (i, el) {
+            if (self.showIndex != i) {
+                el.element.hide();
+            } else {
+                el.element.show();
+            }
+        })
+    },
+
+    setDefaultShowName: function (name) {
+        this.options.defaultShowName = name;
+        return this;
+    },
+
+    getDefaultShowName: function () {
+        return this.options.defaultShowName;
+    },
+
+    getAllCardNames: function () {
+        return BI.map(this.options.items, function (i, item) {
+            return item.cardName;
+        })
+    },
+
+    getShowingCard: function () {
+        if (!BI.isKey(this.showIndex)) {
+            return void 0;
+        }
+        return this.getWidgetByName(this.showIndex);
+    },
+
+    deleteAllCard: function () {
+        var self = this;
+        BI.each(this.getAllCardNames(), function (i, name) {
+            self.deleteCardByName(name);
+        })
+    },
+
+    hideAllCard: function () {
+        BI.each(this._children, function (i, el) {
+            el.invisible();
+        });
+    },
+
+    isAllCardHide: function () {
+        var flag = true;
+        BI.each(this._children, function (i, el) {
+            if (el.isVisible()) {
+                flag = true;
+                return false;
+            }
+        });
+        return flag;
+    },
+});
+$.shortcut('bi.card', BI.CardLayout);/**
+ * 默认的布局方式
+ *
+ * @class BI.DefaultLayout
+ * @extends BI.Layout
+ */
+BI.DefaultLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.DefaultLayout.superclass.props.apply(this, arguments), {
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            items: []
+        });
+    },
+    created: function () {
+        BI.DefaultLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.DefaultLayout.superclass._addElement.apply(this, arguments);
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("default布局不需要resize")
+    },
+
+    populate: function (items) {
+        BI.DefaultLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.default', BI.DefaultLayout);/**
+ * 分隔容器的控件,按照宽度和高度所占比平分整个容器
+ *
+ * @class BI.DivisionLayout
+ * @extends BI.Layout
+ */
+BI.DivisionLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.DivisionLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-division-layout",
+            columns: null,
+            rows: null,
+            items: []
+            //    [
+            //    {
+            //        column: 0,
+            //        row: 0,
+            //        width: 0.25,
+            //        height: 0.33,
+            //        el: {type: 'bi.button', text: 'button1'}
+            //    },
+            //    {
+            //        column: 1,
+            //        row: 1,
+            //        width: 0.25,
+            //        height: 0.33,
+            //        el: {type: 'bi.button', text: 'button2'}
+            //    },
+            //    {
+            //        column: 3,
+            //        row: 2,
+            //        width: 0.25,
+            //        height: 0.33,
+            //        el: {type: 'bi.button', text: 'button3'}
+            //    }
+            //]
+        });
+    },
+    created: function () {
+        BI.DivisionLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        this.stroke(this.opitons.items);
+    },
+
+    addItem: function (item) {
+        // do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function(items){
+        var o = this.options;
+        var rows = o.rows || o.items.length, columns = o.columns || ((o.items[0] && o.items[0].length) | 0);
+        var map = BI.makeArray(rows), widths = {}, heights = {};
+        function firstElement(item, row, col) {
+            if (row === 0) {
+                item.addClass("first-row")
+            }
+            if (col === 0) {
+                item.addClass("first-col");
+            }
+            item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row");
+            item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col");
+            item.addClass("center-element");
+        }
+
+        function firstObject(item, row, col) {
+            var cls = "";
+            if (row === 0) {
+                cls += " first-row";
+            }
+            if (col === 0) {
+                cls += " first-col";
+            }
+            BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row");
+            BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col");
+            item.cls = (item.cls || "") + cls + " center-element";
+        }
+
+        function first(item, row, col) {
+            if (item instanceof BI.Widget) {
+                firstElement(item.element, row, col);
+            } else if (item.el instanceof BI.Widget) {
+                firstElement(item.el.element, row, col);
+            } else if (item.el) {
+                firstObject(item.el, row, col)
+            } else {
+                firstObject(item, row, col);
+            }
+        }
+        BI.each(map, function (i) {
+            map[i] = BI.makeArray(columns);
+        });
+        BI.each(items, function (i, item) {
+            if (BI.isArray(item)) {
+                BI.each(item, function (j, el) {
+                    widths[i] = (widths[i] || 0) + item.width;
+                    heights[j] = (heights[j] || 0) + item.height;
+                    map[i][j] = el;
+                });
+                return;
+            }
+            widths[item.row] = (widths[item.row] || 0) + item.width;
+            heights[item.column] = (heights[item.column] || 0) + item.height;
+            map[item.row][item.column] = item;
+        });
+        for (var i = 0; i < rows; i++) {
+            var totalW = 0;
+            for (var j = 0; j < columns; j++) {
+                if (!map[i][j]) {
+                    throw new Error("缺少item项");
+                }
+                if(!this.hasWidget(this.getName() + i + "_" + j)) {
+                    var w = BI.createWidget(map[i][j]);
+                    this.addWidget(this.getName() + i + "_" + j, w);
+                } else {
+                    w = this.getWidgetByName(this.getName() + i + "_" + j);
+                }
+                var left = totalW * 100 / widths[i];
+                w.element.css({"position": "absolute", "left": left + "%"});
+                if (j > 0) {
+                    var lastW = this.getWidgetByName(this.getName() + i + "_" + (j - 1));
+                    lastW.element.css({"right": (100 - left) + "%"});
+                }
+                if (j == o.columns - 1) {
+                    w.element.css({"right": "0%"});
+                }
+                first(w, i, j);
+                totalW += map[i][j].width;
+            }
+        }
+        for (var j = 0; j < o.columns; j++) {
+            var totalH = 0;
+            for (var i = 0; i < o.rows; i++) {
+                var w = this.getWidgetByName(this.getName() + i + "_" + j);
+                var top = totalH * 100 / heights[j];
+                w.element.css({"top": top + "%"});
+                if (i > 0) {
+                    var lastW = this.getWidgetByName(this.getName() + (i - 1) + "_" + j);
+                    lastW.element.css({"bottom": (100 - top) + "%"});
+                }
+                if (i == o.rows - 1) {
+                    w.element.css({"bottom": "0%"});
+                }
+                totalH += map[i][j].height;
+            }
+        }
+    },
+
+    populate: function (items) {
+        BI.DivisionLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.division', BI.DivisionLayout);/**
+ * 靠左对齐的自由浮动布局
+ * @class BI.FloatLeftLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.FloatLeftLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FloatLeftLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-float-left-layout clearfix",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FloatLeftLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FloatLeftLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "float": "left"});
+        if (BI.isNotNull(item.left)) {
+            w.element.css({"left": item.left});
+        }
+        if (BI.isNotNull(item.right)) {
+            w.element.css({"right": item.right});
+        }
+        if (BI.isNotNull(item.top)) {
+            w.element.css({"top": item.top});
+        }
+        if ((item.lgap || 0) + o.hgap + o.lgap !== 0) {
+            w.element.css("margin-left", (item.lgap || 0) + o.hgap + o.lgap);
+        }
+        if ((item.rgap || 0) + o.hgap + o.rgap !== 0) {
+            w.element.css("margin-right", (item.rgap || 0) + o.hgap + o.rgap);
+        }
+        if ((item.tgap || 0) + o.vgap + o.tgap !== 0) {
+            w.element.css("margin-top", (item.tgap || 0) + o.vgap + o.tgap);
+        }
+        if ((item.bgap || 0) + o.vgap + o.bgap !== 0) {
+            w.element.css("margin-bottom", (item.bgap || 0) + o.vgap + o.bgap);
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.FloatLeftLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.left', BI.FloatLeftLayout);
+
+/**
+ * 靠右对齐的自由浮动布局
+ * @class BI.FloatRightLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.FloatRightLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FloatRightLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-float-right-layout clearfix",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FloatRightLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.FloatRightLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "float": "right"});
+        if (BI.isNotNull(item.left)) {
+            w.element.css({"left": item.left});
+        }
+        if (BI.isNotNull(item.right)) {
+            w.element.css({"right": item.right});
+        }
+        if (BI.isNotNull(item.top)) {
+            w.element.css({"top": item.top});
+        }
+        if ((item.lgap || 0) + o.hgap + o.lgap !== 0) {
+            w.element.css("margin-left", (item.lgap || 0) + o.hgap + o.lgap);
+        }
+        if ((item.rgap || 0) + o.hgap + o.rgap !== 0) {
+            w.element.css("margin-right", (item.rgap || 0) + o.hgap + o.rgap);
+        }
+        if ((item.tgap || 0) + o.vgap + o.tgap !== 0) {
+            w.element.css("margin-top", (item.tgap || 0) + o.vgap + o.tgap);
+        }
+        if ((item.bgap || 0) + o.vgap + o.bgap !== 0) {
+            w.element.css("margin-bottom", (item.bgap || 0) + o.vgap + o.bgap);
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.FloatRightLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.right', BI.FloatRightLayout);/**
+ * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应
+ *
+ * @class BI.BorderLayout
+ * @extends BI.Layout
+ */
+BI.GridLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.GridLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-grid-layout",
+            columns: null,
+            rows: null,
+            items: []
+            /*[
+             {
+             column: 0,
+             row: 0,
+             el: {type: 'bi.button', text: 'button1'}
+             },
+             {
+             column: 1,
+             row: 1,
+             el: {type: 'bi.button', text: 'button2'}
+             },
+             {
+             column: 3,
+             row: 2,
+             el: {type: 'bi.button', text: 'button3'}
+             }
+             ]*/
+        });
+    },
+    created: function () {
+        BI.GridLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("grid布局不需要resize")
+    },
+
+    addItem: function () {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var o = this.options;
+        var rows = o.rows || o.items.length, columns = o.columns || ((o.items[0] && o.items[0].length) | 0);
+        var width = 100 / columns, height = 100 / rows;
+        var els = new Array(rows);
+
+        function firstElement(item, row, col) {
+            if (row === 0) {
+                item.addClass("first-row")
+            }
+            if (col === 0) {
+                item.addClass("first-col");
+            }
+            item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row");
+            item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col");
+            item.addClass("center-element");
+        }
+
+        function firstObject(item, row, col) {
+            var cls = "";
+            if (row === 0) {
+                cls += " first-row";
+            }
+            if (col === 0) {
+                cls += " first-col";
+            }
+            BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row");
+            BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col");
+            item.cls = (item.cls || "") + cls + " center-element";
+        }
+
+        function first(item, row, col) {
+            if (item instanceof BI.Widget) {
+                firstElement(item.element, row, col);
+            } else if (item.el instanceof BI.Widget) {
+                firstElement(item.el.element, row, col);
+            } else if (item.el) {
+                firstObject(item.el, row, col)
+            } else {
+                firstObject(item, row, col);
+            }
+        }
+
+        BI.each(els, function (i) {
+            els[i] = new Array(columns);
+        });
+        BI.each(items, function (i, item) {
+            if (BI.isArray(item)) {
+                BI.each(item, function (j, el) {
+                    els[i][j] = BI.createWidget(el);
+                });
+                return;
+            }
+            els[item.row][item.column] = BI.createWidget(item);
+        });
+        for (var i = 0; i < rows; i++) {
+            for (var j = 0; j < columns; j++) {
+                if (!els[i][j]) {
+                    els[i][j] = BI.createWidget({
+                        type: "bi.layout"
+                    });
+                }
+                first(els[i][j], i, j);
+                els[i][j].element.css({
+                    "position": "absolute",
+                    "top": height * i + "%",
+                    "left": width * j + "%",
+                    "right": (100 - (width * (j + 1))) + "%",
+                    "bottom": (100 - (height * (i + 1))) + "%"
+                });
+                this.addWidget(els[i][j]);
+            }
+        }
+    },
+
+    populate: function (items) {
+        BI.GridLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.grid', BI.GridLayout);/**
+ * 水平布局
+ * @class BI.HorizontalLayout
+ * @extends BI.Layout
+ */
+BI.HorizontalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HorizontalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-horizontal-layout",
+            verticalAlign: "middle",
+            columnSize: [],
+            scrollx: true,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.HorizontalLayout.superclass.created.apply(this, arguments);
+        this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({
+            "position": "relative",
+            "white-space": "nowrap",
+            "border-spacing": "0px",
+            "border": "none",
+            "border-collapse": "separate"
+        });
+        this.$tr = $("<tr>");
+        this.$tr.appendTo(this.$table);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var td;
+        var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i];
+        if (!this.hasWidget(this.getName() + i)) {
+            var w = BI.createWidget(item);
+            w.element.css({"position": "relative", "margin": "0px auto"});
+            td = BI.createWidget({
+                type: "bi.default",
+                tagName: "td",
+                attributes: {
+                    width: width
+                },
+                items: [w]
+            });
+            this.addWidget(this.getName() + i, td);
+        } else {
+            td = this.getWidgetByName(this.getName() + i);
+            td.element.attr("width", width);
+        }
+
+        if (i === 0) {
+            td.element.addClass("first-element");
+        }
+        td.element.css({
+            "position": "relative",
+            "vertical-align": o.verticalAlign,
+            "margin": "0",
+            "padding": "0",
+            "border": "none"
+        });
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return td;
+    },
+
+    _mountChildren: function () {
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$tr.append(frag);
+            this.element.append(this.$table);
+        }
+    },
+
+
+    resize: function () {
+        // console.log("horizontal layout do not need to resize");
+    },
+
+    addItem: function (item) {
+        var w = this._addElement(this.options.items.length, item);
+        w._mount();
+        this.options.items.push(item);
+        w.element.appendTo(this.$tr);
+        return w;
+    },
+
+    populate: function (items) {
+        BI.HorizontalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal', BI.HorizontalLayout);
+
+/**
+ * 水平布局
+ * @class BI.HorizontalCellLayout
+ * @extends BI.Layout
+ */
+BI.HorizontalCellLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HorizontalCellLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-horizontal-cell-layout",
+            scrollable: true,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.HorizontalCellLayout.superclass.created.apply(this, arguments);
+        this.element.css({"display": "table", "vertical-align": "top"});
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.HorizontalCellLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", "display": "table-cell", "vertical-align": "middle"});
+        if (o.hgap + o.lgap > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + "px"
+            })
+        }
+        if (o.hgap + o.rgap > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + "px"
+            })
+        }
+        if (o.vgap + o.tgap > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + "px"
+            })
+        }
+        if (o.vgap + o.bgap > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        // console.log("horizontal do not need to resize");
+    },
+
+    populate: function (items) {
+        BI.HorizontalCellLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal_cell', BI.HorizontalCellLayout);/**
+ * 内联布局
+ * @class BI.InlineLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.InlineLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.InlineLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-inline-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.InlineLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.InlineLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({"position": "relative", display: "inline-block", "*display": "inline", "*zoom": 1});
+        if (o.hgap + o.lgap + (item.lgap || 0) > 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) > 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.tgap + (item.tgap || 0) > 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) > 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function(){
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.InlineLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.inline', BI.InlineLayout);/**
+ * 靠左对齐的自由浮动布局
+ * @class BI.LatticeLayout
+ * @extends BI.Layout
+ *
+ * @cfg {JSON} options 配置属性
+ * @cfg {Number} [hgap=0] 水平间隙
+ * @cfg {Number} [vgap=0] 垂直间隙
+ */
+BI.LatticeLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.LatticeLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-lattice-layout clearfix"
+            //columnSize: [0.2, 0.2, 0.6],
+        });
+    },
+    created: function () {
+        BI.LatticeLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.LatticeLayout.superclass._addElement.apply(this, arguments);
+        if (o.columnSize && o.columnSize[i]) {
+            var width = o.columnSize[i] / BI.sum(o.columnSize) * 100 + "%";
+        } else {
+            var width = 1 / this.options.items.length * 100 + "%"
+        }
+        w.element.css({"position": "relative", "float": "left", "width": width});
+        return w;
+    },
+
+    addItem: function (item) {
+        var w = BI.LatticeLayout.superclass.addItem.apply(this, arguments);
+        this.resize();
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.LatticeLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.lattice', BI.LatticeLayout);/**
+ * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应
+ *
+ * @class BI.TableLayout
+ * @extends BI.Layout
+ */
+BI.TableLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.TableLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-table-layout",
+            scrolly: true,
+            columnSize: [200, 200, 'fill'],
+            rowSize: 30,  //or [30,30,30]
+            hgap: 0,
+            vgap: 0,
+            items: [[
+                {
+                    el: {text: 'label1'}
+                },
+                {
+                    el: {text: 'label2'}
+                },
+                {
+                    el: {text: 'label3'}
+                }
+            ]]
+        });
+    },
+    created: function () {
+        BI.TableLayout.superclass.created.apply(this, arguments);
+        this.rows = 0;
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (idx, arr) {
+        var o = this.options;
+        var abs = [], left = 0, right = 0, i, j;
+
+        function firstElement(item, row, col) {
+            if (row === 0) {
+                item.addClass("first-row")
+            }
+            if (col === 0) {
+                item.addClass("first-col");
+            }
+            item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row");
+            item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col");
+            item.addClass("center-element");
+        }
+
+        function firstObject(item, row, col) {
+            var cls = "";
+            if (row === 0) {
+                cls += " first-row";
+            }
+            if (col === 0) {
+                cls += " first-col";
+            }
+            BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row");
+            BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col");
+            item.cls = (item.cls || "") + cls + " center-element";
+        }
+
+        function first(item, row, col) {
+            if (item instanceof BI.Widget) {
+                firstElement(item.element, row, col);
+            } else if (item.el instanceof BI.Widget) {
+                firstElement(item.el.element, row, col);
+            } else if (item.el) {
+                firstObject(item.el, row, col)
+            } else {
+                firstObject(item, row, col);
+            }
+        }
+
+        for (i = 0; i < arr.length; i++) {
+            if (BI.isNumber(o.columnSize[i])) {
+                first(arr[i], this.rows, i);
+                abs.push(BI.extend({
+                    top: 0,
+                    bottom: 0,
+                    left: o.columnSize[i] <= 1 ? left * 100 + "%" : left,
+                    width: o.columnSize[i] <= 1 ? o.columnSize[i] * 100 + "%" : o.columnSize[i]
+                }, arr[i]));
+                left += o.columnSize[i] + (o.columnSize[i] < 1 ? 0 : o.hgap);
+            } else {
+                break;
+            }
+        }
+        for (j = arr.length - 1; j > i; j--) {
+            if (BI.isNumber(o.columnSize[j])) {
+                first(arr[j], this.rows, j);
+                abs.push(BI.extend({
+                    top: 0,
+                    bottom: 0,
+                    right: o.columnSize[j] <= 1 ? right * 100 + "%" : right,
+                    width: o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j]
+                }, arr[j]))
+                right += o.columnSize[j] + (o.columnSize[j] < 1 ? 0 : o.hgap);
+            } else {
+                throw new Error("只能有一个fill属性的item");
+            }
+        }
+        if (i >= 0 && i < arr.length) {
+            first(arr[i], this.rows, i);
+            abs.push(BI.extend({
+                top: 0,
+                bottom: 0,
+                left: left <= 1 ? left * 100 + "%" : left,
+                right: right <= 1 ? right * 100 + "%" : right
+            }, arr[i]))
+        }
+        var w = BI.createWidget({
+            type: "bi.absolute",
+            height: BI.isArray(o.rowSize) ? o.rowSize[this.rows] : o.rowSize,
+            items: abs
+        });
+        if (this.rows > 0) {
+            this.getWidgetByName(this.getName() + (this.rows - 1)).element.css({
+                "margin-bottom": o.vgap
+            })
+        }
+        w.element.css({
+            "position": "relative"
+        });
+        this.addWidget(this.getName() + (this.rows++), w);
+        return w;
+    },
+
+    resize: function () {
+        // console.log("table布局不需要resize");
+    },
+
+    addItem: function (arr) {
+        if (!BI.isArray(arr)) {
+            throw new Error("item 必须是数组");
+        }
+        return BI.TableLayout.superclass.addItem.apply(this, arguments);
+    },
+
+    populate: function (items) {
+        BI.TableLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.table', BI.TableLayout);/**
+ * 水平tape布局
+ * @class BI.HTapeLayout
+ * @extends BI.Layout
+ */
+BI.HTapeLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HTapeLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-h-tape-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            items: [
+                {
+                    width: 100,
+                    el: {type: 'bi.button', text: 'button1'}
+                },
+                {
+                    width: 'fill',
+                    el: {type: 'bi.button', text: 'button2'}
+                },
+                {
+                    width: 200,
+                    el: {type: 'bi.button', text: 'button3'}
+                }
+            ]
+        });
+    },
+    created: function () {
+        BI.HTapeLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+    addItem: function (item) {
+        // do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        items = BI.compact(items);
+        BI.each(items, function (i, item) {
+            if (!self.hasWidget(self.getName() + i + "")) {
+                var w = BI.createWidget(item);
+                self.addWidget(self.getName() + i + "", w);
+            } else {
+                w = self.getWidgetByName(self.getName() + i + "");
+            }
+            w.element.css({"position": "absolute", top: o.vgap + o.tgap + "px", bottom: o.vgap + o.bgap + "px"});
+        });
+
+        var left = {}, right = {};
+        left[0] = 0;
+        right[items.length - 1] = 0;
+
+        BI.any(items, function (i, item) {
+            var w = self.getWidgetByName(self.getName() + i + "");
+            if (BI.isNull(left[i])) {
+                left[i] = left[i - 1] + items[i - 1].width + 2 * o.hgap + o.lgap + o.rgap;
+            }
+            if (item.width < 1 && item.width >= 0) {
+                w.element.css({"left": left[i] * 100 + "%", width: item.width * 100 + "%"})
+            } else {
+                w.element.css({
+                    "left": left[i] + o.hgap + o.lgap + "px",
+                    width: BI.isNumber(item.width) ? item.width : ""
+                });
+            }
+            if (!BI.isNumber(item.width)) {
+                return true;
+            }
+        });
+        BI.backAny(items, function (i, item) {
+            var w = self.getWidgetByName(self.getName() + i + "");
+            if (BI.isNull(right[i])) {
+                right[i] = right[i + 1] + items[i + 1].width + 2 * o.hgap + o.lgap + o.rgap;
+            }
+            if (item.width < 1 && item.width >= 0) {
+                w.element.css({"right": right[i] * 100 + "%", width: item.width * 100 + "%"})
+            } else {
+                w.element.css({
+                    "right": right[i] + o.hgap + o.rgap + "px",
+                    width: BI.isNumber(item.width) ? item.width : ""
+                });
+            }
+            if (!BI.isNumber(item.width)) {
+                return true;
+            }
+        })
+    },
+
+    populate: function (items) {
+        BI.HTapeLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.htape', BI.HTapeLayout);
+
+/**
+ * 垂直tape布局
+ * @class BI.VTapeLayout
+ * @extends BI.Layout
+ */
+BI.VTapeLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.VTapeLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-v-tape-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            items: [
+                {
+                    height: 100,
+                    el: {type: 'bi.button', text: 'button1'}
+                },
+                {
+                    height: 'fill',
+                    el: {type: 'bi.button', text: 'button2'}
+                },
+                {
+                    height: 200,
+                    el: {type: 'bi.button', text: 'button3'}
+                }
+            ]
+        });
+    },
+    created: function () {
+        BI.VTapeLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    addItem: function (item) {
+        // do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        items = BI.compact(items);
+        BI.each(items, function (i, item) {
+            if (!self.hasWidget(self.getName() + i + "")) {
+                var w = BI.createWidget(item);
+                self.addWidget(self.getName() + i + "", w);
+            } else {
+                w = self.getWidgetByName(self.getName() + i + "");
+            }
+            w.element.css({"position": "absolute", left: o.hgap + o.lgap + "px", right: o.hgap + o.rgap + "px"});
+        });
+
+        var top = {}, bottom = {};
+        top[0] = 0;
+        bottom[items.length - 1] = 0;
+
+        BI.any(items, function (i, item) {
+            var w = self.getWidgetByName(self.getName() + i + "");
+            if (BI.isNull(top[i])) {
+                top[i] = top[i - 1] + items[i - 1].height + 2 * o.vgap + o.tgap + o.bgap;
+            }
+            if (item.height < 1 && item.height >= 0) {
+                w.element.css({"top": top[i] * 100 + "%", height: item.height * 100 + "%"})
+            } else {
+                w.element.css({
+                    "top": top[i] + o.vgap + o.tgap + "px",
+                    height: BI.isNumber(item.height) ? item.height : ""
+                });
+            }
+            if (!BI.isNumber(item.height)) {
+                return true;
+            }
+        });
+        BI.backAny(items, function (i, item) {
+            var w = self.getWidgetByName(self.getName() + i + "");
+            if (BI.isNull(bottom[i])) {
+                bottom[i] = bottom[i + 1] + items[i + 1].height + 2 * o.vgap + o.tgap + o.bgap;
+            }
+            if (item.height < 1 && item.height >= 0) {
+                w.element.css({"bottom": bottom[i] * 100 + "%", height: item.height * 100 + "%"})
+            } else {
+                w.element.css({
+                    "bottom": bottom[i] + o.vgap + o.bgap + "px",
+                    height: BI.isNumber(item.height) ? item.height : ""
+                });
+            }
+            if (!BI.isNumber(item.height)) {
+                return true;
+            }
+        })
+    },
+
+    populate: function (items) {
+        BI.VTapeLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.vtape', BI.VTapeLayout);/**
+ * td布局
+ * @class BI.TdLayout
+ * @extends BI.Layout
+ */
+BI.TdLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.TdLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-td-layout",
+            columnSize: [200, 200, 200],
+            hgap: 0,
+            vgap: 0,
+            items: [[
+                {
+                    el: {text: 'label1'}
+                },
+                {
+                    el: {text: 'label2'}
+                },
+                {
+                    el: {text: 'label3'}
+                }
+            ]]
+        });
+    },
+    created: function () {
+        BI.TdLayout.superclass.created.apply(this, arguments);
+        this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({
+            "position": "relative",
+            "width": "100%",
+            "height": "100%",
+            "border-spacing": "0px",
+            "border": "none",
+            "border-collapse": "separate"
+        });
+        this.rows = 0;
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (idx, arr) {
+        var o = this.options;
+
+        function firstElement(item, row, col) {
+            if (row === 0) {
+                item.addClass("first-row")
+            }
+            if (col === 0) {
+                item.addClass("first-col");
+            }
+            item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row");
+            item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col");
+            item.addClass("center-element");
+        }
+
+        function firstObject(item, row, col) {
+            var cls = "";
+            if (row === 0) {
+                cls += " first-row";
+            }
+            if (col === 0) {
+                cls += " first-col";
+            }
+            BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row");
+            BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col");
+            item.cls = (item.cls || "") + cls + " center-element";
+        }
+
+        function first(item, row, col) {
+            if (item instanceof BI.Widget) {
+                firstElement(item.element, row, col);
+            } else if (item.el instanceof BI.Widget) {
+                firstElement(item.el.element, row, col);
+            } else if (item.el) {
+                firstObject(item.el, row, col)
+            } else {
+                firstObject(item, row, col);
+            }
+        }
+
+        var tr = BI.createWidget({
+            type: "bi.default",
+            tagName: "tr"
+        });
+
+        for (var i = 0; i < arr.length; i++) {
+            var w = BI.createWidget(arr[i]);
+            w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"});
+            first(w, this.rows++, i);
+            var td = BI.createWidget({
+                type: 'bi.default',
+                attributes: {
+                    width: o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i]
+                },
+                tagName: 'td',
+                items: [w]
+            });
+            td.element.css({
+                "position": "relative",
+                "vertical-align": "middle",
+                "margin": "0",
+                "padding": "0",
+                "border": "none"
+            });
+            tr.addItem(td);
+        }
+        this.addWidget(this.getName() + idx, tr);
+        return tr;
+    },
+
+    _mountChildren: function(){
+        var self = this;
+        var frag = document.createDocumentFragment();
+        var hasChild = false;
+        BI.each(this._children, function (i, widget) {
+            if (widget.element !== self.element) {
+                frag.appendChild(widget.element[0]);
+                hasChild = true;
+            }
+        });
+        if (hasChild === true) {
+            this.$table.append(frag);
+            this.element.append(this.$table);
+        }
+    },
+
+    resize: function () {
+        // console.log("td布局不需要resize");
+    },
+
+    addItem: function (arr) {
+        if (!BI.isArray(arr)) {
+            throw new Error("item 必须是数组");
+        }
+        return BI.TdLayout.superclass.addItem.apply(this, arguments);
+    },
+
+    populate: function (items) {
+        BI.TdLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.td', BI.TdLayout);/**
+ * 垂直布局
+ * @class BI.VerticalLayout
+ * @extends BI.Layout
+ */
+BI.VerticalLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.VerticalLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-vertical-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            scrolly: true
+        });
+    },
+    created: function () {
+        BI.VerticalLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _addElement: function (i, item) {
+        var o = this.options;
+        var w = BI.VerticalLayout.superclass._addElement.apply(this, arguments);
+        w.element.css({
+            "position": "relative"
+        });
+        if (o.vgap + o.tgap + (item.tgap || 0) !== 0) {
+            w.element.css({
+                "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.lgap + (item.lgap || 0) !== 0) {
+            w.element.css({
+                "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px"
+            })
+        }
+        if (o.hgap + o.rgap + (item.rgap || 0) !== 0) {
+            w.element.css({
+                "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px"
+            })
+        }
+        if (o.vgap + o.bgap + (item.bgap || 0) !== 0) {
+            w.element.css({
+                "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px"
+            })
+        }
+        return w;
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    populate: function (items) {
+        BI.VerticalLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.vertical', BI.VerticalLayout);/**
+ *
+ * @class BI.WindowLayout
+ * @extends BI.Layout
+ */
+BI.WindowLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.WindowLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-window-layout",
+            columns: 3,
+            rows: 2,
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            columnSize: [100, "fill", 200],
+            rowSize: [100, "fill"],
+            items: [[
+                {
+                    el: {type: 'bi.button', text: 'button1'}
+                },
+                {
+                    el: {type: 'bi.button', text: 'button2'}
+                },
+                {
+                    el: {type: 'bi.button', text: 'button3'}
+                }
+            ]]
+        });
+    },
+    created: function () {
+        BI.WindowLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        this.stroke(this.options.items);
+    },
+
+    addItem: function (item) {
+        // do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var o = this.options;
+        if (BI.isNumber(o.rowSize)) {
+            o.rowSize = BI.makeArray(o.items.length, 1 / o.items.length);
+        }
+        if (BI.isNumber(o.columnSize)) {
+            o.columnSize = BI.makeArray(o.items[0].length, 1 / o.items[0].length);
+        }
+        function firstElement(item, row, col) {
+            if (row === 0) {
+                item.addClass("first-row")
+            }
+            if (col === 0) {
+                item.addClass("first-col");
+            }
+            item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row");
+            item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col");
+            item.addClass("center-element");
+        }
+
+        function firstObject(item, row, col) {
+            var cls = "";
+            if (row === 0) {
+                cls += " first-row";
+            }
+            if (col === 0) {
+                cls += " first-col";
+            }
+            BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row");
+            BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col");
+            item.cls = (item.cls || "") + cls + " center-element";
+        }
+
+        function first(item, row, col) {
+            if (item instanceof BI.Widget) {
+                firstElement(item.element, row, col);
+            } else if (item.el instanceof BI.Widget) {
+                firstElement(item.el.element, row, col);
+            } else if (item.el) {
+                firstObject(item.el, row, col)
+            } else {
+                firstObject(item, row, col);
+            }
+        }
+
+        for (var i = 0; i < o.rows; i++) {
+            for (var j = 0; j < o.columns; j++) {
+                if (!o.items[i][j]) {
+                    throw new Error("缺少item项");
+                }
+                if (!this.hasWidget(this.getName() + i + "_" + j)) {
+                    var w = BI.createWidget(o.items[i][j]);
+                    w.element.css({"position": "absolute"});
+                    this.addWidget(this.getName() + i + "_" + j, w);
+                }
+            }
+        }
+        var left = {}, right = {}, top = {}, bottom = {};
+        left[0] = 0;
+        top[0] = 0;
+        right[o.columns - 1] = 0;
+        bottom[o.rows - 1] = 0;
+        //从上到下
+        for (var i = 0; i < o.rows; i++) {
+            for (var j = 0; j < o.columns; j++) {
+                var wi = this.getWidgetByName(this.getName() + i + "_" + j);
+                if (BI.isNull(top[i])) {
+                    top[i] = top[i - 1] + (o.rowSize[i - 1] < 1 ? o.rowSize[i - 1] : o.rowSize[i - 1] + o.vgap + o.bgap);
+                }
+                var t = top[i] <= 1 ? top[i] * 100 + "%" : top[i] + o.vgap + o.tgap + "px", h = "";
+                if (BI.isNumber(o.rowSize[i])) {
+                    h = o.rowSize[i] <= 1 ? o.rowSize[i] * 100 + "%" : o.rowSize[i] + "px";
+                }
+                wi.element.css({"top": t, height: h});
+                first(wi, i, j);
+            }
+            if (!BI.isNumber(o.rowSize[i])) {
+                break;
+            }
+        }
+        //从下到上
+        for (var i = o.rows - 1; i >= 0; i--) {
+            for (var j = 0; j < o.columns; j++) {
+                var wi = this.getWidgetByName(this.getName() + i + "_" + j);
+                if (BI.isNull(bottom[i])) {
+                    bottom[i] = bottom[i + 1] + (o.rowSize[i + 1] < 1 ? o.rowSize[i + 1] : o.rowSize[i + 1] + o.vgap + o.tgap);
+                }
+                var b = bottom[i] <= 1 ? bottom[i] * 100 + "%" : bottom[i] + o.vgap + o.bgap + "px", h = "";
+                if (BI.isNumber(o.rowSize[i])) {
+                    h = o.rowSize[i] <= 1 ? o.rowSize[i] * 100 + "%" : o.rowSize[i] + "px";
+                }
+                wi.element.css({"bottom": b, height: h});
+                first(wi, i, j);
+            }
+            if (!BI.isNumber(o.rowSize[i])) {
+                break;
+            }
+        }
+        //从左到右
+        for (var j = 0; j < o.columns; j++) {
+            for (var i = 0; i < o.rows; i++) {
+                var wi = this.getWidgetByName(this.getName() + i + "_" + j);
+                if (BI.isNull(left[j])) {
+                    left[j] = left[j - 1] + (o.columnSize[j - 1] < 1 ? o.columnSize[j - 1] : o.columnSize[j - 1] + o.hgap + o.rgap);
+                }
+                var l = left[j] <= 1 ? left[j] * 100 + "%" : left[j] + o.hgap + o.lgap + "px", w = "";
+                if (BI.isNumber(o.columnSize[j])) {
+                    w = o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j] + "px";
+                }
+                wi.element.css({"left": l, width: w});
+                first(wi, i, j);
+            }
+            if (!BI.isNumber(o.columnSize[j])) {
+                break;
+            }
+        }
+        //从右到左
+        for (var j = o.columns - 1; j >= 0; j--) {
+            for (var i = 0; i < o.rows; i++) {
+                var wi = this.getWidgetByName(this.getName() + i + "_" + j);
+                if (BI.isNull(right[j])) {
+                    right[j] = right[j + 1] + (o.columnSize[j + 1] < 1 ? o.columnSize[j + 1] : o.columnSize[j + 1] + o.hgap + o.lgap)
+                }
+                var r = right[j] <= 1 ? right[j] * 100 + "%" : right[j] + o.hgap + o.rgap + "px", w = "";
+                if (BI.isNumber(o.columnSize[j])) {
+                    w = o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j] + "px";
+                }
+                wi.element.css({"right": r, width: w});
+                first(wi, i, j);
+            }
+            if (!BI.isNumber(o.columnSize[j])) {
+                break;
+            }
+        }
+    },
+
+    populate: function (items) {
+        BI.WindowLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.window', BI.WindowLayout);/**
+ * 水平和垂直方向都居中容器, 非自适应,用于宽度高度固定的面板
+ * @class BI.CenterLayout
+ * @extends BI.Layout
+ */
+BI.CenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.CenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-center-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+
+    created: function () {
+        BI.CenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("center布局不需要resize");
+    },
+
+    addItem: function (item) {
+        //do nothing
+        throw new Error("不能添加元素");
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        var list = [];
+        BI.each(items, function (i) {
+            list.push({
+                column: i,
+                row: 0,
+                el: BI.createWidget({
+                    type: "bi.default",
+                    cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "")
+                })
+            });
+        });
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                var w = BI.createWidget(item);
+                w.element.css({
+                    position: "absolute",
+                    left: o.hgap + o.lgap,
+                    right: o.hgap + o.rgap,
+                    top: o.vgap + o.tgap,
+                    bottom: o.vgap + o.bgap,
+                    width: "auto",
+                    height: "auto"
+                });
+                list[i].el.addItem(w);
+            }
+        });
+        BI.createWidget({
+            type: "bi.grid",
+            element: this,
+            columns: list.length,
+            rows: 1,
+            items: list
+        });
+    },
+
+    populate: function (items) {
+        BI.CenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.center', BI.CenterLayout);/**
+ * 浮动布局实现的居中容器
+ * @class BI.FloatCenterLayout
+ * @extends BI.Layout
+ */
+BI.FloatCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.FloatCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-float-center-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.FloatCenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("floatcenter布局不需要resize");
+    },
+
+    addItem: function (item) {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        var list = [], width = 100 / items.length;
+        BI.each(items, function (i) {
+            var widget = BI.createWidget({
+                type: "bi.default"
+            });
+            widget.element.addClass("center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "")).css({
+                width: width + "%",
+                height: "100%"
+            });
+            list.push({
+                el: widget
+            });
+        });
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                var w = BI.createWidget(item);
+                w.element.css({
+                    position: "absolute",
+                    left: o.hgap + o.lgap,
+                    right: o.hgap + o.rgap,
+                    top: o.vgap + o.tgap,
+                    bottom: o.vgap + o.bgap,
+                    width: "auto",
+                    height: "auto"
+                });
+                list[i].el.addItem(w);
+            }
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: list
+        });
+    },
+
+    populate: function (items) {
+        BI.FloatCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.float_center', BI.FloatCenterLayout);/**
+ * 水平和垂直方向都居中容器, 非自适应,用于宽度高度固定的面板
+ * @class BI.HorizontalCenterLayout
+ * @extends BI.Layout
+ */
+BI.HorizontalCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.HorizontalCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-horizontal-center-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.HorizontalCenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("horizontal_center布局不需要resize");
+    },
+
+    addItem: function (item) {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var o = this.options;
+        var list = [];
+        BI.each(items, function (i) {
+            list.push({
+                column: i,
+                row: 0,
+                el: BI.createWidget({
+                    type: "bi.default",
+                    cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "")
+                })
+            });
+        });
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                var w = BI.createWidget(item);
+                w.element.css({
+                    position: "absolute",
+                    left: o.hgap + o.lgap,
+                    right: o.hgap + o.rgap,
+                    top: o.vgap + o.tgap,
+                    bottom: o.vgap + o.bgap,
+                    width: "auto"
+                });
+                list[i].el.addItem(w);
+            }
+        });
+        BI.createWidget({
+            type: "bi.grid",
+            element: this,
+            columns: list.length,
+            rows: 1,
+            items: list
+        });
+    },
+
+    populate: function (items) {
+        BI.HorizontalCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.horizontal_center', BI.HorizontalCenterLayout);/**
+ * 垂直方向都居中容器, 非自适应,用于高度不固定的面板
+ * @class BI.VerticalCenterLayout
+ * @extends BI.Layout
+ */
+BI.VerticalCenterLayout = BI.inherit(BI.Layout, {
+    props: function () {
+        return BI.extend(BI.VerticalCenterLayout.superclass.props.apply(this, arguments), {
+            baseCls: "bi-vertical-center-layout",
+            hgap: 0,
+            vgap: 0,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0
+        });
+    },
+    created: function () {
+        BI.VerticalCenterLayout.superclass.created.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    resize: function () {
+        // console.log("vertical_center布局不需要resize");
+    },
+
+    addItem: function (item) {
+        //do nothing
+        throw new Error("不能添加元素")
+    },
+
+    stroke: function (items) {
+        var self = this, o = this.options;
+        var list = [];
+        BI.each(items, function (i) {
+            list.push({
+                column: 0,
+                row: i,
+                el: BI.createWidget({
+                    type: "bi.default",
+                    cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "")
+                })
+            });
+        });
+        BI.each(items, function (i, item) {
+            if (!!item) {
+                var w = BI.createWidget(item);
+                w.element.css({
+                    position: "absolute",
+                    left: o.hgap + o.lgap,
+                    right: o.hgap + o.rgap,
+                    top: o.vgap + o.tgap,
+                    bottom: o.vgap + o.bgap,
+                    height: "auto"
+                });
+                list[i].el.addItem(w);
+            }
+        });
+        BI.createWidget({
+            type: "bi.grid",
+            element: this,
+            columns: 1,
+            rows: list.length,
+            items: list
+        });
+    },
+
+    populate: function (items) {
+        BI.VerticalCenterLayout.superclass.populate.apply(this, arguments);
+        this._mount();
+    }
+});
+$.shortcut('bi.vertical_center', BI.VerticalCenterLayout);/**
+ * 保存数据,将js里面用到的常量数据都分离
+ *
+ */
+BI.Data = Data = {};
+
+/**
+ * 存放bi里面通用的一些常量
+ * @type {{}}
+ */
+Data.Constant = BI.Constant = BICst = {};
+BICst.HISTORY_VERSION = {};
+BICst.HISTORY_VERSION.VERSION_4_0 = 4.0;
+BICst.HISTORY_VERSION.VERSION_4_1 = 4.01;
+BICst.REPORT_AUTH = {};
+BICst.REPORT_AUTH.NONE = 0;
+BICst.REPORT_AUTH.EDIT = 1;
+BICst.REPORT_AUTH.VIEW = 2;
+BICst.TARGET_STYLE = {};
+BICst.TARGET_STYLE.ICON_STYLE = {};
+BICst.TARGET_STYLE.ICON_STYLE.NONE = 1;
+BICst.TARGET_STYLE.ICON_STYLE.POINT = 2;
+BICst.TARGET_STYLE.ICON_STYLE.ARROW = 3;
+BICst.TARGET_STYLE.NUM_LEVEL = {};
+BICst.TARGET_STYLE.NUM_LEVEL.NORMAL = 1;
+BICst.TARGET_STYLE.NUM_LEVEL.TEN_THOUSAND = 2;
+BICst.TARGET_STYLE.NUM_LEVEL.MILLION = 3;
+BICst.TARGET_STYLE.NUM_LEVEL.YI = 4;
+BICst.TARGET_STYLE.NUM_LEVEL.PERCENT = 5;
+BICst.TARGET_STYLE.FORMAT = {};
+BICst.TARGET_STYLE.FORMAT.NORMAL = -1;
+BICst.TARGET_STYLE.FORMAT.ZERO2POINT = 0;
+BICst.TARGET_STYLE.FORMAT.ONE2POINT = 1;
+BICst.TARGET_STYLE.FORMAT.TWO2POINT = 2;
+BICst.MULTI_PATH_STATUS = {};
+BICst.MULTI_PATH_STATUS.NEED_GENERATE_CUBE = 0;
+BICst.MULTI_PATH_STATUS.NOT_NEED_GENERATE_CUBE = 1;
+BICst.CUSTOM_GROUP = {};
+BICst.CUSTOM_GROUP.UNGROUP2OTHER = {};
+BICst.CUSTOM_GROUP.UNGROUP2OTHER.NOTSELECTED = 0;
+BICst.CUSTOM_GROUP.UNGROUP2OTHER.SELECTED = 1;
+BICst.REPORT_STATUS = {};
+BICst.REPORT_STATUS.APPLYING = 1;
+BICst.REPORT_STATUS.HANGOUT = 2;
+BICst.REPORT_STATUS.NORMAL = 3;
+BICst.FIELD_ID = {};
+BICst.FIELD_ID.HEAD = "81c48028-1401-11e6-a148-3e1d05defe78";
+BICst.TREE_LABEL = {};
+BICst.TREE_LABEL.TREE_LABEL_ITEM_COUNT_NUM = 40;
+BICst.TREE = {};
+BICst.TREE.TREE_REQ_TYPE = {};
+BICst.TREE.TREE_REQ_TYPE.INIT_DATA = 0;
+BICst.TREE.TREE_REQ_TYPE.SEARCH_DATA = 1;
+BICst.TREE.TREE_REQ_TYPE.SELECTED_DATA = 3;
+BICst.TREE.TREE_REQ_TYPE.ADJUST_DATA = 2;
+BICst.TREE.TREE_REQ_TYPE.DISPLAY_DATA = 4;
+BICst.TREE.TREE_ITEM_COUNT_PER_PAGE = 100;
+BICst.BUSINESS_TABLE_TYPE = {};
+BICst.BUSINESS_TABLE_TYPE.NORMAL = 0;
+BICst.EXPANDER_TYPE = {};
+BICst.EXPANDER_TYPE.NONE = false;
+BICst.EXPANDER_TYPE.ALL = true;
+BICst.SORT = {};
+BICst.SORT.ASC = 0;
+BICst.SORT.DESC = 1;
+BICst.SORT.CUSTOM = 2;
+BICst.SORT.NONE = 3;
+BICst.SORT.NUMBER_ASC = 4;
+BICst.SORT.NUMBER_DESC = 5;
+BICst.TABLE_PAGE_OPERATOR = {};
+BICst.TABLE_PAGE_OPERATOR.ALL_PAGE = -1;
+BICst.TABLE_PAGE_OPERATOR.REFRESH = 0;
+BICst.TABLE_PAGE_OPERATOR.COLUMN_PRE = 1;
+BICst.TABLE_PAGE_OPERATOR.COLUMN_NEXT = 2;
+BICst.TABLE_PAGE_OPERATOR.ROW_PRE = 3;
+BICst.TABLE_PAGE_OPERATOR.ROW_NEXT = 4;
+BICst.TABLE_PAGE_OPERATOR.EXPAND = 5;
+BICst.TABLE_PAGE = {};
+BICst.TABLE_PAGE.VERTICAL_PRE = 0;
+BICst.TABLE_PAGE.VERTICAL_NEXT = 1;
+BICst.TABLE_PAGE.HORIZON_PRE = 2;
+BICst.TABLE_PAGE.HORIZON_NEXT = 3;
+BICst.TABLE_PAGE.TOTAL_PAGE = 4;
+BICst.TABLE_WIDGET = {};
+BICst.TABLE_WIDGET.GROUP_TYPE = 1;
+BICst.TABLE_WIDGET.CROSS_TYPE = 2;
+BICst.TABLE_WIDGET.COMPLEX_TYPE = 3;
+BICst.REGION = {};
+BICst.REGION.DIMENSION1 = "10000";
+BICst.REGION.DIMENSION2 = "20000";
+BICst.REGION.TARGET1 = "30000";
+BICst.REGION.TARGET2 = "40000";
+BICst.REGION.TARGET3 = "50000";
+BICst.EXPORT = {};
+BICst.EXPORT.EXCEL = 1;
+BICst.EXPORT.PDF = 2;
+BICst.WIDGET = {};
+BICst.WIDGET.TABLE = 1;
+BICst.WIDGET.CROSS_TABLE = 2;
+BICst.WIDGET.COMPLEX_TABLE = 3;
+BICst.WIDGET.DETAIL = 4;
+BICst.WIDGET.AXIS = 5;
+BICst.WIDGET.ACCUMULATE_AXIS = 6;
+BICst.WIDGET.PERCENT_ACCUMULATE_AXIS = 7;
+BICst.WIDGET.COMPARE_AXIS = 8;
+BICst.WIDGET.FALL_AXIS = 9;
+BICst.WIDGET.BAR = 10;
+BICst.WIDGET.ACCUMULATE_BAR = 11;
+BICst.WIDGET.COMPARE_BAR = 12;
+BICst.WIDGET.LINE = 13;
+BICst.WIDGET.AREA = 14;
+BICst.WIDGET.ACCUMULATE_AREA = 15;
+BICst.WIDGET.PERCENT_ACCUMULATE_AREA = 16;
+BICst.WIDGET.COMPARE_AREA = 17;
+BICst.WIDGET.RANGE_AREA = 18;
+BICst.WIDGET.COMBINE_CHART = 19;
+BICst.WIDGET.MULTI_AXIS_COMBINE_CHART = 20;
+BICst.WIDGET.PIE = 21;
+BICst.WIDGET.DONUT = 22;
+BICst.WIDGET.MAP = 23;
+BICst.WIDGET.GIS_MAP = 24;
+BICst.WIDGET.DASHBOARD = 25;
+BICst.WIDGET.BUBBLE = 26;
+BICst.WIDGET.FORCE_BUBBLE = 27;
+BICst.WIDGET.SCATTER = 28;
+BICst.WIDGET.RADAR = 29;
+BICst.WIDGET.ACCUMULATE_RADAR = 30;
+BICst.WIDGET.FUNNEL = 31;
+BICst.WIDGET.RECT_TREE = 39;
+BICst.WIDGET.MULTI_PIE = 40;
+BICst.WIDGET.HEAT_MAP = 65;
+BICst.WIDGET.PARETO = 66;
+BICst.WIDGET.STRING = 32;
+BICst.WIDGET.NUMBER = 33;
+BICst.WIDGET.TREE = 34;
+BICst.WIDGET.SINGLE_SLIDER = 35;
+BICst.WIDGET.INTERVAL_SLIDER = 36;
+BICst.WIDGET.LIST_LABEL = 37;
+BICst.WIDGET.TREE_LABEL = 38;
+BICst.WIDGET.STRING_LIST = 59;
+BICst.WIDGET.TREE_LIST = 60;
+BICst.WIDGET.DATE_PANE = 61;
+BICst.WIDGET.DATE = 48;
+BICst.WIDGET.YEAR = 49;
+BICst.WIDGET.QUARTER = 50;
+BICst.WIDGET.MONTH = 51;
+BICst.WIDGET.YMD = 52;
+BICst.WIDGET.QUERY = 53;
+BICst.WIDGET.RESET = 54;
+BICst.WIDGET.CONTENT = 55;
+BICst.WIDGET.IMAGE = 56;
+BICst.WIDGET.WEB = 57;
+BICst.WIDGET.GENERAL_QUERY = 58;
+BICst.WIDGET.TABLE_SHOW = 64;
+BICst.WIDGET.NONE = -1;
+BICst.TARGET_TYPE = {};
+BICst.TARGET_TYPE.CAL_POSITION = {};
+BICst.TARGET_TYPE.CAL_POSITION.ALL = 0;
+BICst.TARGET_TYPE.CAL_POSITION.INGROUP = 1;
+BICst.TARGET_TYPE.CAL_VALUE = {};
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE = {};
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE.VALUE = 0;
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE.RATE = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE = {};
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.SUM = 0;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.MAX = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.MIN = 2;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.AVG = 3;
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE = {};
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE.ASC = 0;
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE.DESC = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUM_OF_ALL = 0;
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUM_OF_ABOVE = 2;
+BICst.TARGET_TYPE.CAL_VALUE.RANK = 3;
+BICst.TARGET_TYPE.CAL = {};
+BICst.TARGET_TYPE.CAL.FORMULA = 0;
+BICst.TARGET_TYPE.CAL.CONFIGURATION = 1;
+BICst.TARGET_TYPE.STRING = 1;
+BICst.TARGET_TYPE.NUMBER = 2;
+BICst.TARGET_TYPE.DATE = 3;
+BICst.TARGET_TYPE.COUNTER = 4;
+BICst.TARGET_TYPE.FORMULA = 5;
+BICst.TARGET_TYPE.YEAR_ON_YEAR_RATE = 6;
+BICst.TARGET_TYPE.MONTH_ON_MONTH_RATE = 7;
+BICst.TARGET_TYPE.YEAR_ON_YEAR_VALUE = 8;
+BICst.TARGET_TYPE.MONTH_ON_MONTH_VALUE = 9;
+BICst.TARGET_TYPE.SUM_OF_ABOVE = 10;
+BICst.TARGET_TYPE.SUM_OF_ABOVE_IN_GROUP = 11;
+BICst.TARGET_TYPE.SUM_OF_ALL = 12;
+BICst.TARGET_TYPE.SUM_OF_ALL_IN_GROUP = 13;
+BICst.TARGET_TYPE.RANK = 14;
+BICst.TARGET_TYPE.RANK_IN_GROUP = 15;
+BICst.DIMENSION_FILTER_DATE = {};
+BICst.DIMENSION_FILTER_DATE.BELONG_VALUE = 98;
+BICst.DIMENSION_FILTER_DATE.NOT_BELONG_VALUE = 99;
+BICst.DIMENSION_FILTER_DATE.IS_NULL = 100;
+BICst.DIMENSION_FILTER_DATE.NOT_NULL = 101;
+BICst.DIMENSION_FILTER_DATE.TOP_N = 102;
+BICst.DIMENSION_FILTER_DATE.BOTTOM_N = 103;
+BICst.DIMENSION_FILTER_DATE.CONTAIN = 104;
+BICst.DIMENSION_FILTER_DATE.NOT_CONTAIN = 105;
+BICst.DIMENSION_FILTER_DATE.BEGIN_WITH = 106;
+BICst.DIMENSION_FILTER_DATE.END_WITH = 107;
+BICst.FILTER_TYPE = {};
+BICst.FILTER_TYPE.AND = 80;
+BICst.FILTER_TYPE.OR = 81;
+BICst.FILTER_TYPE.FORMULA = 82;
+BICst.FILTER_TYPE.EMPTY_FORMULA = 90;
+BICst.FILTER_TYPE.EMPTY_CONDITION = 91;
+BICst.FILTER_TYPE.NUMBER_SUM = 83;
+BICst.FILTER_TYPE.NUMBER_AVG = 84;
+BICst.FILTER_TYPE.NUMBER_MAX = 85;
+BICst.FILTER_TYPE.NUMBER_MIN = 86;
+BICst.FILTER_TYPE.NUMBER_COUNT = 87;
+BICst.FILTER_TYPE.TREE_FILTER = 88;
+BICst.FILTER_TYPE.COLUMNFILTER = 89;
+BICst.FILTER_TYPE.DIMENSION_TARGET_VALUE_FILTER = 96;
+BICst.FILTER_TYPE.DIMENSION_SELF_FILTER = 97;
+BICst.FILTER_DATE = {};
+BICst.FILTER_DATE.BELONG_DATE_RANGE = 64;
+BICst.FILTER_DATE.BELONG_WIDGET_VALUE = 65;
+BICst.FILTER_DATE.NOT_BELONG_DATE_RANGE = 66;
+BICst.FILTER_DATE.NOT_BELONG_WIDGET_VALUE = 67;
+BICst.FILTER_DATE.MORE_THAN = 68;
+BICst.FILTER_DATE.LESS_THAN = 69;
+BICst.FILTER_DATE.EQUAL_TO = 70;
+BICst.FILTER_DATE.NOT_EQUAL_TO = 71;
+BICst.FILTER_DATE.IS_NULL = 72;
+BICst.FILTER_DATE.NOT_NULL = 73;
+BICst.FILTER_DATE.EARLY_THAN = 74;
+BICst.FILTER_DATE.LATER_THAN = 75;
+BICst.FILTER_DATE.CONTAINS = 76;
+BICst.FILTER_DATE.CONTAINS_DAY = 77;
+BICst.FILTER_DATE.DAY_EQUAL_TO = 78;
+BICst.FILTER_DATE.DAY_NOT_EQUAL_TO = 79;
+BICst.TARGET_FILTER_NUMBER = {};
+BICst.TARGET_FILTER_NUMBER.EQUAL_TO = 48;
+BICst.TARGET_FILTER_NUMBER.NOT_EQUAL_TO = 49;
+BICst.TARGET_FILTER_NUMBER.BELONG_VALUE = 50;
+BICst.TARGET_FILTER_NUMBER.BELONG_USER = 51;
+BICst.TARGET_FILTER_NUMBER.NOT_BELONG_VALUE = 52;
+BICst.TARGET_FILTER_NUMBER.NOT_BELONG_USER = 53;
+BICst.TARGET_FILTER_NUMBER.IS_NULL = 54;
+BICst.TARGET_FILTER_NUMBER.NOT_NULL = 55;
+BICst.TARGET_FILTER_NUMBER.CONTAINS = 56;
+BICst.TARGET_FILTER_NUMBER.NOT_CONTAINS = 57;
+BICst.TARGET_FILTER_NUMBER.LARGE_THAN_CAL_LINE = 58;
+BICst.TARGET_FILTER_NUMBER.LARGE_OR_EQUAL_CAL_LINE = 59;
+BICst.TARGET_FILTER_NUMBER.SMALL_THAN_CAL_LINE = 60;
+BICst.TARGET_FILTER_NUMBER.SMALL_OR_EQUAL_CAL_LINE = 61;
+BICst.TARGET_FILTER_NUMBER.TOP_N = 62;
+BICst.TARGET_FILTER_NUMBER.BOTTOM_N = 63;
+BICst.TARGET_FILTER_STRING = {};
+BICst.TARGET_FILTER_STRING.BELONG_VALUE = 32;
+BICst.TARGET_FILTER_STRING.BELONG_USER = 33;
+BICst.TARGET_FILTER_STRING.NOT_BELONG_VALUE = 34;
+BICst.TARGET_FILTER_STRING.NOT_BELONG_USER = 35;
+BICst.TARGET_FILTER_STRING.CONTAIN = 36;
+BICst.TARGET_FILTER_STRING.NOT_CONTAIN = 37;
+BICst.TARGET_FILTER_STRING.IS_NULL = 38;
+BICst.TARGET_FILTER_STRING.NOT_NULL = 39;
+BICst.TARGET_FILTER_STRING.BEGIN_WITH = 40;
+BICst.TARGET_FILTER_STRING.END_WITH = 41;
+BICst.TARGET_FILTER_STRING.NOT_BEGIN_WITH = 42;
+BICst.TARGET_FILTER_STRING.NOT_END_WITH = 43;
+BICst.TARGET_FILTER_STRING.VAGUE_CONTAIN = 46;
+BICst.TARGET_FILTER_STRING.NOT_VAGUE_CONTAIN = 47;
+BICst.DIMENSION_FILTER_NUMBER = {};
+BICst.DIMENSION_FILTER_NUMBER.BELONG_VALUE = 16;
+BICst.DIMENSION_FILTER_NUMBER.BELONG_USER = 17;
+BICst.DIMENSION_FILTER_NUMBER.NOT_BELONG_VALUE = 18;
+BICst.DIMENSION_FILTER_NUMBER.NOT_BELONG_USER = 19;
+BICst.DIMENSION_FILTER_NUMBER.MORE_THAN_AVG = 20;
+BICst.DIMENSION_FILTER_NUMBER.LESS_THAN_AVG = 21;
+BICst.DIMENSION_FILTER_NUMBER.IS_NULL = 22;
+BICst.DIMENSION_FILTER_NUMBER.NOT_NULL = 23;
+BICst.DIMENSION_FILTER_NUMBER.TOP_N = 24;
+BICst.DIMENSION_FILTER_NUMBER.BOTTOM_N = 25;
+BICst.DIMENSION_FILTER_STRING = {};
+BICst.DIMENSION_FILTER_STRING.BELONG_VALUE = 0;
+BICst.DIMENSION_FILTER_STRING.BELONG_USER = 1;
+BICst.DIMENSION_FILTER_STRING.NOT_BELONG_VALUE = 2;
+BICst.DIMENSION_FILTER_STRING.NOT_BELONG_USER = 3;
+BICst.DIMENSION_FILTER_STRING.CONTAIN = 4;
+BICst.DIMENSION_FILTER_STRING.NOT_CONTAIN = 5;
+BICst.DIMENSION_FILTER_STRING.IS_NULL = 6;
+BICst.DIMENSION_FILTER_STRING.NOT_NULL = 7;
+BICst.DIMENSION_FILTER_STRING.BEGIN_WITH = 8;
+BICst.DIMENSION_FILTER_STRING.END_WITH = 9;
+BICst.DIMENSION_FILTER_STRING.TOP_N = 10;
+BICst.DIMENSION_FILTER_STRING.BOTTOM_N = 11;
+BICst.DIMENSION_FILTER_STRING.NOT_BEGIN_WITH = 12;
+BICst.DIMENSION_FILTER_STRING.NOT_END_WITH = 13;
+BICst.DIMENSION_FILTER_STRING.VAGUE_CONTAIN = 14;
+BICst.DIMENSION_FILTER_STRING.NOT_VAGUE_CONTAIN = 15;
+BICst.GROUP = {};
+BICst.GROUP.NO_GROUP = 0;
+BICst.GROUP.AUTO_GROUP = 3;
+BICst.GROUP.CUSTOM_GROUP = 4;
+BICst.GROUP.CUSTOM_NUMBER_GROUP = 5;
+BICst.GROUP.Y = 6;
+BICst.GROUP.S = 7;
+BICst.GROUP.M = 8;
+BICst.GROUP.W = 9;
+BICst.GROUP.YMD = 10;
+BICst.GROUP.YD = 11;
+BICst.GROUP.MD = 12;
+BICst.GROUP.YMDHMS = 13;
+BICst.GROUP.ID_GROUP = 14;
+BICst.GROUP.HOUR = 15;
+BICst.GROUP.MINUTE = 16;
+BICst.GROUP.SECOND = 17;
+BICst.GROUP.WEEK_COUNT = 18;
+BICst.GROUP.D = 19;
+BICst.GROUP.YM = 20;
+BICst.GROUP.YW = 21;
+BICst.GROUP.YMDH = 22;
+BICst.GROUP.YMDHM = 23;
+BICst.GROUP.YS = 24;
+BICst.SUMMARY_TYPE = {};
+BICst.SUMMARY_TYPE.SUM = 0;
+BICst.SUMMARY_TYPE.MAX = 1;
+BICst.SUMMARY_TYPE.MIN = 2;
+BICst.SUMMARY_TYPE.AVG = 3;
+BICst.SUMMARY_TYPE.COUNT = 4;
+BICst.SUMMARY_TYPE.APPEND = 5;
+BICst.SUMMARY_TYPE.RECORD_COUNT = 6;
+BICst.BI_REPORT = {};
+BICst.BI_REPORT.NULL = 0;
+BICst.BI_REPORT.SUBMITED = 1;
+BICst.BI_REPORT.PUBLISHED = 2;
+BICst.VERSION = "4.0.2";
+BICst.SYSTEM_TIME = "__system_time-3e1d05defe78__";
+
+BICst.ETL_ADD_COLUMN_TYPE = {};
+BICst.ETL_ADD_COLUMN_TYPE.FORMULA = "formula";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_DIFF = "date_diff";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_YEAR = "date_year";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_SEASON = "date_season";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_MONTH = "date_month";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_CPP = "expr_same_period";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_LP = "expr_last_period";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_CPP_PERCENT = "expr_same_period_percent";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_LP_PERCENT = "expr_last_period_percent";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_SUM = "expr_sum";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_ACC = "expr_acc";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_RANK = "expr_rank";
+BICst.ETL_ADD_COLUMN_TYPE.GROUP = "group_value";
+BICst.ETL_ADD_COLUMN_TYPE.SINGLE_VALUE = "single_value";
+BICst.ETL_ADD_COLUMN_TYPE.VALUE_CONVERT = "value_convert";
+BICst.JSON_KEYS = {};
+BICst.JSON_KEYS.STATISTIC_ELEMENT = "_src";
+BICst.JSON_KEYS.FILED_MAX_VALUE = "max";
+BICst.JSON_KEYS.FIELD_MIN_VALUE = "min";
+BICst.JSON_KEYS.FILTER_VALUE = "filter_value";
+BICst.JSON_KEYS.FILTER_CONDITION = "condition";
+BICst.JSON_KEYS.FILTER_AND_OR = "andor";
+BICst.JSON_KEYS.FILTER_TYPE = "filter_type";
+BICst.JSON_KEYS.FIELD_ID = "field_id";
+BICst.JSON_KEYS.FIELD_TYPE = "field_type";
+BICst.JSON_KEYS.FIELD_VALUE = "field_value";
+BICst.JSON_KEYS.FIELD_NAME = "field_name";
+BICst.JSON_KEYS.TYPE = "type";
+BICst.JSON_KEYS.VALUE = "value";
+BICst.JSON_KEYS.EXPANDER = "expander";
+BICst.JSON_KEYS.EXPANDER_X = "x";
+BICst.JSON_KEYS.EXPANDER_Y = "y";
+BICst.JSON_KEYS.CLICKEDVALUE = "clickedvalue";
+BICst.JSON_KEYS.SETTTINGS = "settings";
+BICst.JSON_KEYS.ID = "id";
+BICst.JSON_KEYS.TABLES = "tables";
+BICst.JSON_KEYS.TABLE = "table";
+BICst.JSON_KEYS.FIELDS = "fields";
+BICst.JSON_KEYS.FIELD = "field";
+BICst.JSON_KEYS.ETL_TYPE = "etl_type";
+BICst.JSON_KEYS.ETL_VALUE = "etl_value";
+BICst.JSON_KEYS.TABLE_TYPE = "table_type";
+BICst.JSON_KEYS.HAS_NEXT = "hasNext";
+BICst.JSON_KEYS.CONNECTION_NAME = "connection_name";
+BICst.JSON_KEYS.TABLE_NAME = "table_name";
+BICst.JSON_KEYS.TRAN_NAME = "tran_name";
+BICst.JSON_KEYS.TABLE_TRAN_NAME = "table_tran_name";
+BICst.JSON_KEYS.FIELD_TRAN_NAME = "field_tran_name";
+BICst.JSON_KEYS.GROUP_NAME = "group_name";
+BICst.JSON_KEYS.PACKAGE_NAME = "package_name";
+BICst.JSON_KEYS.RELATIONS = "relations";
+BICst.JSON_KEYS.TRANSLATIONS = "translations";
+BICst.JSON_KEYS.UPDATESETTING = "update_setting";
+BICst.JSON_KEYS.PACKAGE_ID = "package_id";
+BICst.JSON_KEYS.CONNECTION_SET = "connectionSet";
+BICst.JSON_KEYS.PRIMARY_KEY_MAP = "primKeyMap";
+BICst.JSON_KEYS.FOREIGN_KEY_MAP = "foreignKeyMap";
+
+BICst.DATA_CONFIG_DESIGN = {};
+BICst.DATA_CONFIG_DESIGN.NO = 0;
+BICst.DATA_CONFIG_DESIGN.YES = 1;
+BICst.DATA_CONFIG_AUTHORITY = {};
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER = {};
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.NODE = "__package_manager_node__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.PAGE = "__package_manager_page__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.SERVER_CONNECTION = "__package_server_connection__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.DATA_CONNECTION = "__package_data_connection__";
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION = {};
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION.NODE = "__data_connection_node__";
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION.PAGE = "__data_connection_page__";
+BICst.DATA_CONFIG_AUTHORITY.MULTI_PATH_SETTING = "__multi_path_setting__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_AUTHORITY = "__package_authority__";
+BICst.DATA_CONFIG_AUTHORITY.FINE_INDEX_UPDATE = "__fine_index_update__";
+BICst.GLOBAL_UPDATE_TYPE = {};
+BICst.GLOBAL_UPDATE_TYPE.PART_UPDATE = "_part_update_";
+BICst.GLOBAL_UPDATE_TYPE.COMPLETE_UPDATE = "_complete_update_";
+BICst.GLOBAL_UPDATE_TYPE.META_UPDATE = "_meta_update_";
+BICst.CUBE_UPDATE_TYPE = {};
+BICst.CUBE_UPDATE_TYPE.GLOBAL_UPDATE = "__global_update__";
+BICst.CUBE_UPDATE_TYPE.SINGLETABLE_UPDATE = "__singleTable_update__";
+BICst.SINGLE_TABLE_UPDATE = {};
+BICst.SINGLE_TABLE_UPDATE.TOGETHER = 0;
+BICst.SINGLE_TABLE_UPDATE.NEVER = 1;
+BICst.SINGLE_TABLE_UPDATE_TYPE = {};
+BICst.SINGLE_TABLE_UPDATE_TYPE.ALL = 0;
+BICst.SINGLE_TABLE_UPDATE_TYPE.PART = 1;
+BICst.SINGLE_TABLE_UPDATE_TYPE.NEVER = 2;
+BICst.UPDATE_FREQUENCY = {};
+BICst.UPDATE_FREQUENCY.EVER_DAY = 0;
+BICst.UPDATE_FREQUENCY.EVER_SUNDAY = 1;
+BICst.UPDATE_FREQUENCY.EVER_MONDAY = 2;
+BICst.UPDATE_FREQUENCY.EVER_TUESDAY = 3;
+BICst.UPDATE_FREQUENCY.EVER_WEDNESDAY = 4;
+BICst.UPDATE_FREQUENCY.EVER_THURSDAY = 5;
+BICst.UPDATE_FREQUENCY.EVER_FRIDAY = 6;
+BICst.UPDATE_FREQUENCY.EVER_SATURDAY = 7;
+BICst.UPDATE_FREQUENCY.EVER_MONTH = 10;
+BICst.REQ_DATA_TYPE = {};
+BICst.REQ_DATA_TYPE.REQ_GET_ALL_DATA = -1;
+BICst.REQ_DATA_TYPE.REQ_GET_DATA_LENGTH = 0;
+BICst.TRANS_TYPE = {};
+BICst.TRANS_TYPE.READ_FROM_DB = "db";
+BICst.TRANS_TYPE.READ_FROM_TABLEDATA = "tabledata";
+BICst.TRANS_TYPE.CHOOSE = "choose";
+BICst.CONNECTION = {};
+BICst.CONNECTION.ETL_CONNECTION = "__FR_BI_ETL__";
+BICst.CONNECTION.SERVER_CONNECTION = "__FR_BI_SERVER__";
+BICst.CONNECTION.SQL_CONNECTION = "__FR_BI_SQL__";
+BICst.CONNECTION.EXCEL_CONNECTION = "__FR_BI_EXCEL__";
+BICst.COLUMN = {};
+BICst.COLUMN.NUMBER = 32;
+BICst.COLUMN.STRING = 16;
+BICst.COLUMN.DATE = 48;
+BICst.COLUMN.COUNTER = 64;
+BICst.COLUMN.ROW = 80;
+BICst.CLASS = {};
+BICst.CLASS.INTEGER = 0;
+BICst.CLASS.LONG = 1;
+BICst.CLASS.DOUBLE = 2;
+BICst.CLASS.FLOAT = 3;
+BICst.CLASS.DATE = 4;
+BICst.CLASS.STRING = 5;
+BICst.CLASS.BOOLEAN = 6;
+BICst.CLASS.TIMESTAMP = 7;
+BICst.CLASS.DECIMAL = 8;
+BICst.CLASS.TIME = 9;
+BICst.CLASS.BYTE = 10;
+BICst.CLASS.ROW = 16;
+BICst.SYSTEM_USER_NAME = "__system_user_name__";
+BICst.LAST_UPDATE_TIME = "__last_update_time__";
+BICst.CURRENT_UPDATE_TIME = "__current_update_time__";
+
+BICst.FUNCTION = {};
+BICst.FUNCTION.TEXT = 1;
+BICst.FUNCTION.MATH = 2;
+BICst.FUNCTION.DATE = 3;
+BICst.FUNCTION.ARRAY = 4;
+BICst.FUNCTION.LOGIC = 5;
+BICst.FUNCTION.OTHER = 6;/**
+ * 缓冲池
+ * @type {{Buffer: {}}}
+ */
+;
+(function () {
+    var Buffer = {};
+    var MODE = false;//设置缓存模式为关闭
+
+    Data.BufferPool = {
+        put: function (name, cache) {
+            if (BI.isNotNull(Buffer[name])) {
+                throw new Error("Buffer Pool has the key already!");
+            }
+            Buffer[name] = cache;
+        },
+
+        get: function (name) {
+            return Buffer[name];
+        },
+    };
+})();/**
+ * 共享池
+ * @type {{Shared: {}}}
+ */
+;
+(function () {
+    var _Shared = {};
+    Data.SharingPool = {
+        _Shared: _Shared,
+        put: function (name, shared) {
+            _Shared[name] = shared;
+        },
+
+        cat: function () {
+            var args = Array.prototype.slice.call(arguments, 0),
+                copy = _Shared;
+            for (var i = 0; i < args.length; i++) {
+                copy = copy[args[i]];
+            }
+            return copy;
+        },
+
+        get: function () {
+            return BI.deepClone(this.cat.apply(this, arguments));
+        },
+
+        remove: function (key) {
+            delete _Shared[key];
+        }
+    };
+})();Data.Req = {
+
+};
+Data.Source = BISource = {
+
+};//工程配置
+$(function () {
+    //注册布局
+    var isSupportFlex = BI.isSupportCss3("flex");
+    BI.Plugin.registerWidget("bi.horizontal", function (ob) {
+        if (isSupportFlex) {
+            return BI.extend(ob, {type: "bi.flex_horizontal"});
+        } else {
+            return ob;
+        }
+    });
+    BI.Plugin.registerWidget("bi.center_adapt", function (ob) {
+        if (isSupportFlex && ob.items && ob.items.length <= 1) {
+            //有滚动条的情况下需要用到flex_wrapper_center布局
+            if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) {
+                //不是IE用flex_wrapper_center布局
+                if (!BI.isIE()) {
+                    return BI.extend(ob, {type: "bi.flex_wrapper_center"});
+                }
+                return ob;
+            }
+            return BI.extend(ob, {type: "bi.flex_center"});
+        } else {
+            return ob;
+        }
+    });
+    BI.Plugin.registerWidget("bi.vertical_adapt", function (ob) {
+        if (isSupportFlex) {
+            //有滚动条的情况下需要用到flex_wrapper_center布局
+            if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) {
+                //不是IE用flex_wrapper_center布局
+                if (!BI.isIE()) {
+                    return BI.extend({}, ob, {type: "bi.flex_wrapper_vertical_center"});
+                }
+                return ob;
+            }
+            return BI.extend(ob, {type: "bi.flex_vertical_center"});
+        } else {
+            return ob;
+        }
+    });
+    BI.Plugin.registerWidget("bi.float_center_adapt", function (ob) {
+        if (isSupportFlex) {
+            //有滚动条的情况下需要用到flex_wrapper_center布局
+            if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) {
+                //不是IE用flex_wrapper_center布局
+                if (!BI.isIE()) {
+                    return BI.extend({}, ob, {type: "bi.flex_wrapper_center"});
+                }
+                return ob;
+            }
+            return BI.extend(ob, {type: "bi.flex_center"});
+        } else {
+            return ob;
+        }
+    });
+
+    //注册控件
+    BI.Plugin.registerWidget("bi.grid_table", function (ob) {
+        //IE下滚动条滑动效果不好,禁止掉
+        if (BI.isIE() || BI.isFireFox()) {
+            return BI.extend(ob, {type: "bi.quick_grid_table"});
+        } else {
+            return ob;
+        }
+    });
+    BI.Plugin.registerWidget("bi.collection_table", function (ob) {
+        //IE下滚动条滑动效果不好,禁止掉
+        if (BI.isIE() || BI.isFireFox()) {
+            return BI.extend(ob, {type: "bi.quick_collection_table"});
+        } else {
+            return ob;
+        }
+    });
+});
\ No newline at end of file
diff --git a/dist/cursor/cursor_drag_hand.cur b/dist/cursor/cursor_drag_hand.cur
new file mode 100644
index 000000000..aab39cfbe
Binary files /dev/null and b/dist/cursor/cursor_drag_hand.cur differ
diff --git a/dist/cursor/cursor_hand.cur b/dist/cursor/cursor_hand.cur
new file mode 100644
index 000000000..94d112079
Binary files /dev/null and b/dist/cursor/cursor_hand.cur differ
diff --git a/dist/cursor/cursor_left_right.cur b/dist/cursor/cursor_left_right.cur
new file mode 100644
index 000000000..54ff9f2ae
Binary files /dev/null and b/dist/cursor/cursor_left_right.cur differ
diff --git a/dist/font/iconfont.eot b/dist/font/iconfont.eot
new file mode 100644
index 000000000..9e2cbf610
Binary files /dev/null and b/dist/font/iconfont.eot differ
diff --git a/dist/font/iconfont.svg b/dist/font/iconfont.svg
new file mode 100644
index 000000000..90429dbe1
--- /dev/null
+++ b/dist/font/iconfont.svg
@@ -0,0 +1,674 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+Created by FontForge 20120731 at Mon Feb  6 14:42:36 2017
+ By admin
+</metadata>
+<defs>
+<font id="bi" horiz-adv-x="1024" >
+  <font-face 
+    font-family="bi"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="1024"
+    panose-1="2 0 6 3 0 0 0 0 0 0"
+    ascent="896"
+    descent="-128"
+    x-height="792"
+    bbox="0 -218 1308 896"
+    underline-thickness="0"
+    underline-position="0"
+    unicode-range="U+0078-E6EC"
+  />
+<missing-glyph 
+ />
+    <glyph glyph-name=".notdef" 
+ />
+    <glyph glyph-name=".notdef" 
+ />
+    <glyph glyph-name=".null" horiz-adv-x="0" 
+ />
+    <glyph glyph-name="nonmarkingreturn" horiz-adv-x="341" 
+ />
+    <glyph glyph-name="x" unicode="x" horiz-adv-x="1001" 
+d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
+t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
+t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
+    <glyph glyph-name="sousuo" unicode="&#xe604;" 
+d="M894 -7l-239 242q73 77 73 205t-86.5 217t-212.5 89t-215 -90t-89 -216q0 -127 88 -213.5t214 -86.5q115 0 188 57l241 -244q7 -6 16 -6t20 11q7 7 8 17.5t-6 17.5zM173 443.5q0 105.5 74 180t178.5 74.5t178.5 -74.5t74 -180t-74 -180t-178.5 -74.5t-178.5 74.5t-74 180
+z" />
+    <glyph glyph-name="dian" unicode="&#xe606;" 
+d="M352 287.5q0 -66.5 47 -113t113.5 -46.5t113 46.5t46.5 113t-46.5 113.5t-113 47t-113.5 -47t-47 -113.5z" />
+    <glyph glyph-name="jinzhi" unicode="&#xe6dc;" 
+d="M512 709q-111 0 -205.5 -54.5t-149 -149t-54.5 -205.5t54.5 -205.5t149 -149t205.5 -54.5t205.5 54.5t149 149t54.5 205.5t-54.5 205.5t-149 149t-205.5 54.5zM819 300q0 -98 -57 -178l-428 428q80 57 178 57q127 0 217 -90t90 -217zM205 300q0 99 58 179l428 -428
+q-80 -58 -179 -58q-127 0 -217 90t-90 217z" />
+    <glyph glyph-name="ordinaryset" unicode="&#xe697;" 
+d="M955 374h-44q-15 0 -29.5 10.5t-18.5 24.5l-26 62q-7 13 -4.5 30.5t13.5 28.5l32 31q10 11 10 26.5t-10 25.5l-53 52q-11 11 -26 11t-26 -11l-31 -31q-11 -11 -28.5 -13.5t-30.5 4.5l-62 26q-14 4 -24.5 18.5t-10.5 29.5v44q0 15 -11 26t-26 11h-74q-15 0 -26 -11
+t-11 -26v-44q0 -16 -10.5 -30t-24.5 -18l-62 -26q-13 -7 -30.5 -4.5t-28.5 13.5l-31 32q-11 10 -26 10t-26 -10l-52 -53q-11 -10 -11 -25.5t11 -26.5l31 -31q11 -11 13.5 -28.5t-4.5 -30.5l-26 -62q-4 -14 -18.5 -24.5t-29.5 -10.5h-44q-15 0 -26 -11t-11 -26v-74
+q0 -15 11 -26t26 -11h44q16 0 30 -10.5t18 -24.5l26 -62q7 -13 4.5 -30.5t-13.5 -28.5l-32 -31q-10 -11 -10 -26.5t10 -25.5l53 -53q11 -10 26 -10t26 10l31 32q11 11 28.5 13.5t30.5 -5.5l62 -25q14 -4 24.5 -18.5t10.5 -29.5v-44q0 -15 11 -26t26 -11h74q15 0 26 11t11 26
+v44q0 15 10.5 29.5t24.5 18.5l62 25q13 8 30.5 5.5t28.5 -13.5l31 -32q11 -10 26 -10t26 10l53 53q10 11 10 26t-10 26l-32 31q-11 11 -13.5 28.5t4.5 30.5l26 62q4 14 18 24.5t30 10.5h44q15 0 26 11t11 26v74q0 15 -11 26t-26 11zM697 300q0 -76 -54 -130.5t-130.5 -54.5
+t-131 54.5t-54.5 131t54.5 130.5t131 54t130.5 -54t54 -131v0z" />
+    <glyph glyph-name="zuojiantou" unicode="&#xe601;" 
+d="M287 301l435 434q6 7 15.5 7t16.5 -7t7 -16.5t-7 -15.5l-418 -418l414 -414q7 -7 7 -16.5t-6.5 -16.5t-16 -7t-16.5 7l-431 430q-6 7 -6 16.5t6 16.5z" />
+    <glyph glyph-name="youjiantou" unicode="&#xe602;" 
+d="M754 301l-434 434q-7 7 -16.5 7t-16 -7t-6.5 -16.5t6 -15.5l418 -418l-414 -414q-7 -7 -7 -16.5t7 -16.5t16.5 -7t16.5 7l430 430q7 7 7 16.5t-7 16.5z" />
+    <glyph glyph-name="guanbi" unicode="&#xe600;" 
+d="M552 299l231 232q8 8 8 19.5t-8 19.5t-19 8t-19 -8l-232 -232l-232 232q-8 8 -19 8t-19 -8t-8 -19.5t8 -19.5l231 -232l-231 -232q-8 -8 -8 -19t8 -19t19 -8t19 8l232 231l232 -231q8 -8 19 -8t19 8t8 19t-8 19z" />
+    <glyph glyph-name="xiala" unicode="&#xe608;" 
+d="M762 446l-219 -322q-12 -17 -32.5 -17t-31.5 17l-219 322q-10 16 0.5 31.5t31.5 15.5h438q21 0 31.5 -15.5t0.5 -31.5z" />
+    <glyph glyph-name="wenhao" unicode="&#xe69a;" 
+d="M512 813q-104 0 -199 -40.5t-163.5 -109t-109 -163.5t-40.5 -199t40.5 -199t109 -163.5t163.5 -109t199 -40.5t199 40.5t163.5 109t109 163.5t40.5 199t-40.5 199t-109 163.5t-163.5 109t-199 40.5zM512 -147q-91 0 -174 35.5t-143 95.5t-95.5 143t-35.5 174t35.5 174
+t95.5 143t143 95.5t174 35.5t174 -35.5t143 -95.5t95.5 -143t35.5 -174t-35.5 -174t-95.5 -143t-143 -95.5t-174 -35.5zM412 410q1 4 2.5 10.5t10 23t19.5 28.5t33.5 20t49.5 5q35 -4 53.5 -18t21 -31t0 -30t-7.5 -21q-4 -11 -56 -55.5t-60 -64.5q-14 -32 -14 -102h89
+q1 1 0 7.5t1.5 19t6 25.5t13.5 26.5t24 21.5q20 12 40.5 32t39.5 47.5t23.5 57.5t-7.5 62q-41 66 -84.5 85.5t-108.5 16.5q-64 -2 -113 -38t-67 -116zM463 142h93v-102h-93v102z" />
+    <glyph glyph-name="iconfontcolor91" unicode="&#xe692;" 
+d="M512 812q-139 0 -257 -68.5t-186.5 -186.5t-68.5 -257t68.5 -257t186.5 -186.5t257 -68.5t257 68.5t186.5 186.5t68.5 257t-68.5 257t-186.5 186.5t-257 68.5zM800 268h-256v-256q0 -14 -9.5 -23t-22.5 -9t-22.5 9t-9.5 23v256h-256q-14 0 -23 9.5t-9 22.5t9.5 22.5
+t22.5 9.5h256v256q0 14 9.5 23t22.5 9t22.5 -9t9.5 -23v-256h256q14 0 23 -9.5t9 -22.5t-9 -22.5t-23 -9.5z" />
+    <glyph glyph-name="xiala1" unicode="&#xe603;" 
+d="M512 40l-279 279l46 45l233 -233l233 233l46 -45z" />
+    <glyph glyph-name="shujuku" unicode="&#xe693;" 
+d="M802 682q-119 51 -292 51t-292 -51q-59 -26 -90.5 -59.5t-31.5 -71.5v-505q0 -38 31.5 -72t90.5 -59q119 -51 292 -51t292 51q59 25 90.5 59t31.5 72v505q0 38 -31.5 71.5t-90.5 59.5zM756 460q-110 -38 -246 -38t-246 38q-55 18 -84.5 42t-29.5 49t29.5 49t84.5 42
+q110 38 246 38t246 -38q55 -18 84 -42t29 -49t-29 -49t-84 -42zM756 304q-110 -37 -246 -37t-246 37q-55 19 -84.5 42.5t-29.5 49.5v62q54 -40 147 -64q97 -25 213 -25t213 25q93 24 146 64v-62q0 -26 -29 -49.5t-84 -42.5zM756 129q-110 -37 -246 -37t-246 37
+q-55 19 -84.5 42.5t-29.5 49.5v82q54 -41 147 -65q97 -25 213 -25t213 25q93 24 146 65v-82q0 -26 -29 -49.5t-84 -42.5zM510 -83q-136 0 -246 37q-55 19 -84.5 42.5t-29.5 49.5v82q54 -41 147 -65q97 -25 213 -25t213 25q93 24 146 65v-82q0 -26 -29 -49.5t-84 -42.5
+q-110 -37 -246 -37z" />
+    <glyph glyph-name="shanchu" unicode="&#xe605;" 
+d="M576 672v64h-192v-64h-256v-128h704v128h-256zM192 -32q0 -53 37.5 -90.5t90.5 -37.5h320q53 0 90.5 37.5t37.5 90.5v512h-576v-512zM576 416h64v-448h-64v448zM448 416h64v-448h-64v448zM320 416h64v-448h-64v448z" />
+    <glyph glyph-name="yangshishezhihuihua" unicode="&#xe60c;" 
+d="M784 748l-54 -118l-122 -19l88 -92l-21 -131l109 62l109 -62l-21 131l88 92l-122 19l-54 118v0zM192 280l-40 -86l-88 -14l64 -67l-15 -95l79 45l79 -45l-15 95l64 67l-88 14l-40 86v0zM391 19l-25 -54l-56 -9l41 -43l-10 -60l50 28l51 -28l-10 60l41 43l-56 9l-26 54v0z
+M176 546l84 90l84 -90l-84 -90l-84 90v0zM260 701l-149 -159l149 -159l494 -531l149 159l-643 690v0z" />
+    <glyph glyph-name="guolvhuihua" unicode="&#xe60f;" 
+d="M448 254l-384 494h896l-384 -494v-274l-128 -128v402v0z" />
+    <glyph glyph-name="fuzhihuihua" unicode="&#xe610;" 
+d="M128 -84h640v-64h-640v64v0zM64 620h64v-768h-64v768v0zM704 748h-448q-18 0 -31 -7t-19 -16.5t-9.5 -19t-4.5 -16.5v-7v-638q0 -28 16 -44t32 -18l16 -2h576q28 0 44 16t18 32l2 16v512l-192 192v0zM320 300h448v-64h-448v64v0zM320 428h448v-64h-448v64v0zM320 172h448
+v-64h-448v64v0zM704 556v128l128 -128h-128v0z" />
+    <glyph glyph-name="tongjigeshuyilaihuihua" unicode="&#xe611;" 
+d="M960 556l-64 64l-512 -384l-256 192l-64 -64l320 -384l576 576v0z" />
+    <glyph glyph-name="zhibiaolaizizhengchang" unicode="&#xe612;" 
+d="M384 428h256v-64h-256v64v0zM448 556h128v-64h-128v64v0zM960 -84h-896v391l192 441h512l192 -441v-391v0zM832 300l-126 320h-379l-135 -320h198l63 -128h126l63 128h190v0z" />
+    <glyph glyph-name="tubiaoleixingzhengchang" unicode="&#xe613;" 
+d="M64 364h256v-512h-256v512v0zM704 556h256v-704h-256v704v0zM384 748h256v-896h-256v896v0z" />
+    <glyph glyph-name="iocnduijitiaoxingtu" unicode="&#xe60a;" 
+d="M128 727h43v-854h-43v854zM43 1h938v-42h-938v42zM171 641h170v-128h-170v128zM427 641h213v-128h-213v128zM171 428h384v-128h-384v128zM640 428h299v-128h-299v128zM171 215h213v-128h-213v128zM469 215h256v-128h-256v128z" />
+    <glyph glyph-name="iocnfuyong" unicode="&#xe60b;" 
+d="M299 513v-597h682v597h-682zM939 -41h-598v426h598v-426zM43 727v-598h213v43h-171v427h598v-43h42v171h-682z" />
+    <glyph glyph-name="iocngengduo" unicode="&#xe60d;" 
+d="M43 556h469v-43h-469v43zM85 471h43v-256h-43v256zM128 300h341v-43h-341v43zM427 471h42v-214h-42v214zM128 471h299v-43h-299v43zM128 385h299v-42h-299v42zM256 513h43v-341h-43v341zM128 215h43v-43h-43v43zM171 172h85v-43h-85v43zM43 129h128v-42h-128v42zM256 129
+h256v-42h-256v42zM555 129h170v-42h-170v42zM725 599h43v-86h-43v86zM768 556h171v-43h-171v43zM853 513h43v-42h-43v42zM811 471h42v-43h-42v43zM768 428h43v-43h-43v43zM725 385h43v-42h-43v42zM683 428h42v-43h-42v43zM640 471h43v-43h-43v43zM683 513h42v-42h-42v42z
+M555 428h85v-43h-85v43zM640 343h85v-43h-85v43zM555 300h85v-43h-85v43zM683 257h85v-42h-85v42zM768 300h43v-43h-43v43zM811 343h170v-43h-170v43zM853 385h43v-42h-43v42zM896 428h43v-43h-43v43zM939 300h42v-43h-42v43zM896 257h43v-42h-43v42zM811 257h42v-85h-42v85
+zM853 215h43v-43h-43v43zM725 172h86v-43h-86v43z" />
+    <glyph glyph-name="iocnhuizongbiao" unicode="&#xe60e;" 
+d="M43 684v-768h938v768h-938zM939 -41h-854v682h854v-682zM128 599h341v-598h-341v598zM512 599h384v-171h-384v171zM512 385h384v-170h-384v170zM512 172h384v-171h-384v171z" />
+    <glyph glyph-name="iocnleidatu" unicode="&#xe614;" 
+d="M512 674l419 -285l-160 -473h-518l-160 472zM512 727l-469 -322l179 -532h580l179 532l-469 322v0zM512 520l257 -180l-98 -296h-318l-98 295zM512 573l-307 -217l117 -355h380l117 355l-307 217v0zM512 623l-213 -341l426 -341z" />
+    <glyph glyph-name="iocnmingxibiao" unicode="&#xe615;" 
+d="M43 684v-768h938v768h-938zM939 -41h-854v682h854v-682zM512 599h384v-171h-384v171zM512 385h384v-170h-384v170zM512 172h384v-171h-384v171zM128 599h341v-171h-341v171zM128 385h341v-170h-341v170zM128 172h341v-171h-341v171z" />
+    <glyph glyph-name="iocnnianfenkongjian" unicode="&#xe616;" 
+d="M171 343h128v-214h-128v214zM683 343h128v-214h-128v214zM811 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM896 -84h-811v640h811v-640zM341 257h43v-42h-43v42zM384 300h85v-43h-85v43zM469 257h43v-42h-43v42zM512 215h85v-43h-85v43zM597 257h43v-42
+h-43v42z" />
+    <glyph glyph-name="iocnbaocun" unicode="&#xe617;" 
+d="M848 748h-784v-896h896v784zM512 620h128v-192h-128v192zM832 -20h-640v640h64v-256h448v256h98l30 -30v-610z" />
+    <glyph glyph-name="iocnbingtu" unicode="&#xe618;" 
+d="M512 242v410q-79 0 -155 -32.5t-134 -87t-93.5 -131.5t-35.5 -159q0 -112 53.5 -206.5t147.5 -149.5t205.5 -55t205.5 55t148.5 149.5t54.5 206.5q0 111 -36 183zM922 543q-52 104 -147.5 165.5t-219.5 61.5v-411z" />
+    <glyph glyph-name="iocnchaxun" unicode="&#xe609;" 
+d="M0 684h43v-768h-43v768zM0 684h1024v-43h-1024v43zM981 641h43v-725h-43v725zM0 -41h1024v-43h-1024v43zM85 513h384v-42h-384v42zM256 556h43v-213h-43v213zM171 471h42v-43h-42v43zM128 428h43v-43h-43v43zM85 385h43v-42h-43v42zM341 471h43v-43h-43v43zM384 428h43
+v-43h-43v43zM427 385h42v-42h-42v42zM128 343h43v-214h-43v214zM171 257h213v-42h-213v42zM384 343h43v-214h-43v214zM171 343h213v-43h-213v43zM171 172h213v-43h-213v43zM85 87h384v-43h-384v43zM512 556h43v-43h-43v43zM555 513h42v-42h-42v42zM597 471h43v-43h-43v43z
+M640 556h43v-85h-43v85zM683 513h256v-42h-256v42zM896 513h43v-426h-43v426zM811 87h85v-43h-85v43zM512 428h85v-43h-85v43zM555 428h42v-384h-42v384zM640 428h43v-341h-43v341zM640 172h213v-43h-213v43zM683 428h170v-43h-170v43zM811 428h42v-299h-42v299zM683 300
+h128v-43h-128v43z" />
+    <glyph glyph-name="iocnchexiao" unicode="&#xe619;" 
+d="M762 -212q25 46 42 94t23.5 99t0 97.5t-32.5 88t-69 71t-114 46t-164 14.5v-254l-384 384l384 384v-248q105 2 190 -17.5t141.5 -55.5t94.5 -86.5t52.5 -109.5t11 -124.5t-25 -131t-60 -130.5t-90.5 -121z" />
+    <glyph glyph-name="iocnchongzhi" unicode="&#xe61a;" 
+d="M0 684h43v-768h-43v768zM0 684h1024v-43h-1024v43zM981 641h43v-725h-43v725zM0 -41h1024v-43h-1024v43zM128 513h171v-42h-171v42zM299 556h128v-43h-128v43zM256 471h43v-384h-43v384zM85 428h384v-43h-384v43zM128 385h43v-170h-43v170zM171 343h256v-43h-256v43z
+M384 385h43v-170h-43v170zM171 257h256v-42h-256v42zM128 172h299v-43h-299v43zM85 87h384v-43h-384v43zM563 556h43v-85h-43v85zM597 556h342v-43h-342v43zM904 513h43v-85h-43v85zM776 513h43v-85h-43v85zM691 513h43v-85h-43v85zM555 471h384v-43h-384v43zM725 428h43
+v-171h-43v171zM555 385h384v-42h-384v42zM597 300h43v-213h-43v213zM597 300h299v-43h-299v43zM853 300v0v-213v0v213zM853 300h43v-213h-43v213zM725 172h43v-128h-43v128zM555 87h384v-43h-384v43z" />
+    <glyph glyph-name="iocnriqikongjian" unicode="&#xe61b;" 
+d="M427 471h128v-128h-128v128zM597 471h128v-128h-128v128zM768 471h128v-128h-128v128zM256 129h128v-128h-128v128zM427 129h128v-128h-128v128zM597 129h128v-128h-128v128zM427 300h128v-128h-128v128zM597 300h128v-128h-128v128zM768 300h128v-128h-128v128zM256 300
+h128v-128h-128v128zM896 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM981 -84h-810v640h810v-640z" />
+    <glyph glyph-name="iocnriqiqujiankongjian" unicode="&#xe61c;" 
+d="M811 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM896 -84h-811v640h811v-640zM171 471h128v-43h-128v43zM256 428h43v-85h-43v85zM171 385h85v-42h-85v42zM171 343h42v-86h-42v86zM213 300h86v-43h-86v43zM341 428h43v-128h-43v128zM427 428h42v-128h-42
+v128zM384 471h43v-43h-43v43zM384 300h43v-43h-43v43zM341 471h43v-43h-43v43zM341 300h43v-43h-43v43zM427 300h42v-43h-42v43zM427 471h42v-43h-42v43zM512 471h85v-43h-85v43zM555 428h42v-171h-42v171zM512 300h128v-43h-128v43zM683 471h42v-86h-42v86zM683 385h128
+v-42h-128v42zM768 343h43v-86h-43v86zM683 300h85v-43h-85v43zM725 471h86v-43h-86v43zM171 172h42v-128h-42v128zM256 172h43v-128h-43v128zM213 215h43v-43h-43v43zM213 44h43v-43h-43v43zM171 215h42v-43h-42v43zM171 44h42v-43h-42v43zM256 44h43v-43h-43v43zM256 215
+h43v-43h-43v43zM341 215h86v-43h-86v43zM384 172h43v-171h-43v171zM341 44h128v-43h-128v43zM512 172h43v-128h-43v128zM597 172h43v-128h-43v128zM555 215h42v-43h-42v43zM555 44h42v-43h-42v43zM512 215h43v-43h-43v43zM512 44h43v-43h-43v43zM597 44h43v-43h-43v43z
+M597 215h43v-43h-43v43zM683 215h85v-43h-85v43zM725 172h43v-171h-43v171zM683 44h128v-43h-128v43z" />
+    <glyph glyph-name="iocnsandiantu" unicode="&#xe61d;" 
+d="M952 769l29 -29l-909 -909l-29 29zM341 44h128v-128h-128v128zM43 -41h128v-128h-128v128zM43 215h128v-128h-128v128zM256 343h128v-128h-128v128zM213 599h128v-128h-128v128zM555 641h128v-128h-128v128zM640 428h128v-128h-128v128zM811 44h128v-128h-128v128z
+M853 641h128v-128h-128v128z" />
+    <glyph glyph-name="iocnshukongjian" unicode="&#xe61e;" 
+d="M341 599l-170 -299l-171 299h341zM427 599h597v-86h-597v86zM427 343h597v-86h-597v86zM427 87h597v-86h-597v86z" />
+    <glyph glyph-name="iocnshuzhileixing" unicode="&#xe61f;" 
+d="M43 428h42v-85h-42v85zM85 471h43v-86h-43v86zM128 513h85v-384h-85v384zM341 471h86v-43h-86v43zM384 513h213v-42h-213v42zM555 471h85v-128h-85v128zM512 385h85v-85h-85v85zM469 343h43v-86h-43v86zM512 300h43v-43h-43v43zM427 300h85v-85h-85v85zM384 257h85v-85
+h-85v85zM341 215h43v-86h-43v86zM384 172h256v-43h-256v43zM683 471h85v-43h-85v43zM725 513h214v-42h-214v42zM896 471h85v-86h-85v86zM811 385h128v-42h-128v42zM896 343h85v-128h-85v128zM896 215h43v-43h-43v43zM683 215h85v-43h-85v43zM725 172h171v-43h-171v43z" />
+    <glyph glyph-name="iocntiaoxingtu" unicode="&#xe620;" 
+d="M128 727h43v-854h-43v854zM43 1h938v-42h-938v42zM171 641h384v-128h-384v128zM171 428h682v-128h-682v128zM171 215h512v-128h-512v128z" />
+    <glyph glyph-name="iocnwenben" unicode="&#xe621;" 
+d="M85 599h128v-299h-42v-43h42h86h42v43h-42v299h128v-43h42v128h-42h-342h-42v-128h42v43zM555 513h426v-85h-426v85zM555 343h426v-86h-426v86zM43 172h938v-85h-938v85zM43 1h938v-85h-938v85zM555 684h426v-85h-426v85z" />
+    <glyph glyph-name="iocnwenbenkongjian" unicode="&#xe622;" 
+d="M43 215h85v-128h-85v128zM85 385h86v-170h-86v170zM128 471h128v-86h-128v86zM128 215h213v-43h-213v43zM256 172h85v-85h-85v85zM213 385h86v-170h-86v170zM384 471h85v-384h-85v384zM597 428h86v-128h-86v128zM597 257h86v-128h-86v128zM469 471h171v-43h-171v43z
+M469 300h171v-43h-171v43zM469 129h171v-42h-171v42zM725 385h86v-213h-86v213zM768 428h85v-43h-85v43zM811 471h170v-43h-170v43zM939 428h85v-43h-85v43zM768 172h85v-43h-85v43zM811 129h170v-42h-170v42zM939 172h85v-43h-85v43z" />
+    <glyph glyph-name="iocnyibiaopan" unicode="&#xe623;" 
+d="M243 -127h84q-113 68 -177.5 165t-64.5 219q0 116 57.5 214.5t155.5 155.5t214 57t214 -57t155.5 -155.5t57.5 -214.5q0 -122 -64.5 -219t-177.5 -165h84q93 66 146.5 166.5t53.5 217.5q0 96 -37 183t-100 149.5t-150 100t-182 37.5t-182 -37.5t-150 -100t-100 -149.5
+t-37 -183q0 -117 53.5 -217.5t146.5 -166.5zM213 -41h598v-86h-598v86zM469 727h86v-128h-86v128zM85 343h86v-85h-86v85zM853 343h86v-85h-86v85zM469 428h86v-469h-86v469zM512 428zM469 428.5q0 17.5 12.5 30t30.5 12.5t30.5 -12.5t12.5 -30t-12.5 -30t-30.5 -12.5
+t-30.5 12.5t-12.5 30z" />
+    <glyph glyph-name="iocnyuanhuantu" unicode="&#xe624;" 
+d="M555 597q124 -16 191 -97.5t67 -199.5q0 -61 -20 -111l149 -86q40 88 40 197q0 122 -53 225t-151 168.5t-223 75.5v-172zM469 3q-100 17 -177.5 102.5t-77.5 194.5t77.5 194.5t177.5 102.5v172q-79 -8 -156 -48t-136.5 -101.5t-96 -146t-36.5 -173.5t36.5 -173.5t96 -146
+t136.5 -101.5t156 -48v172zM749 115q-75 -96 -194 -112v-172q97 9 190 62.5t150 134.5z" />
+    <glyph glyph-name="iocnzhongzuo" unicode="&#xe625;" 
+d="M576 564v248l384 -384l-384 -384v254q-93 2 -164 -14.5t-114 -46t-69 -71t-32.5 -88t0 -97.5t23.5 -99t42 -94q-52 56 -90.5 121t-60 130.5t-25 131t11 124.5t52.5 109.5t94.5 86.5t141.5 55.5t190 17.5z" />
+    <glyph glyph-name="iocnzuobiaozhoutu" unicode="&#xe626;" 
+d="M128 727h43v-854h-43v854zM43 1h938v-42h-938v42zM256 385h128v-384h-128v384zM469 684h128v-683h-128v683zM683 513h128v-512h-128v512z" />
+    <glyph glyph-name="iocnnianjidukongjian" unicode="&#xe627;" 
+d="M811 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM896 -84h-811v640h811v-640zM171 471h128v-43h-128v43zM256 428h43v-85h-43v85zM171 385h85v-42h-85v42zM171 343h42v-86h-42v86zM213 300h86v-43h-86v43zM341 428h43v-128h-43v128zM427 428h42v-128h-42
+v128zM384 471h43v-43h-43v43zM384 300h43v-43h-43v43zM341 471h43v-43h-43v43zM341 300h43v-43h-43v43zM427 300h42v-43h-42v43zM427 471h42v-43h-42v43zM512 471h85v-43h-85v43zM555 428h42v-171h-42v171zM512 300h128v-43h-128v43zM683 471h42v-86h-42v86zM683 385h128
+v-42h-128v42zM768 343h43v-86h-43v86zM683 300h85v-43h-85v43zM725 471h86v-43h-86v43zM341 172h43v-128h-43v128zM427 172h42v-128h-42v128zM384 215h43v-43h-43v43zM384 44h43v-43h-43v43zM341 215h43v-43h-43v43zM341 44h43v-43h-43v43zM427 44h42v-43h-42v43zM427 215
+h42v-43h-42v43zM512 215h85v-43h-85v43zM555 172h42v-171h-42v171zM512 44h128v-43h-128v43z" />
+    <glyph glyph-name="iocnnianyuekongjian" unicode="&#xe628;" 
+d="M811 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM896 -84h-811v640h811v-640zM171 385h128v-42h-128v42zM256 343h43v-128h-43v128zM171 257h85v-42h-85v42zM171 215h42v-128h-42v128zM213 129h86v-42h-86v42zM341 343h43v-214h-43v214zM427 343h42v-214
+h-42v214zM384 385h43v-42h-43v42zM384 129h43v-42h-43v42zM341 385h43v-42h-43v42zM341 129h43v-42h-43v42zM427 129h42v-42h-42v42zM427 385h42v-42h-42v42zM512 385h85v-42h-85v42zM555 343h42v-256h-42v256zM512 129h128v-42h-128v42zM683 385h42v-128h-42v128zM683 257
+h128v-42h-128v42zM768 215h43v-128h-43v128zM683 129h85v-42h-85v42zM725 385h86v-42h-86v42z" />
+    <glyph glyph-name="iocnnianyuerikongjian" unicode="&#xe629;" 
+d="M811 727v-43h-128v43h-384v-43h-128v43h-128v-854h896v854h-128zM896 -84h-811v640h811v-640zM171 471h128v-43h-128v43zM256 428h43v-85h-43v85zM171 385h85v-42h-85v42zM171 343h42v-86h-42v86zM213 300h86v-43h-86v43zM341 428h43v-128h-43v128zM427 428h42v-128h-42
+v128zM384 471h43v-43h-43v43zM384 300h43v-43h-43v43zM341 471h43v-43h-43v43zM341 300h43v-43h-43v43zM427 300h42v-43h-42v43zM427 471h42v-43h-42v43zM512 471h85v-43h-85v43zM555 428h42v-171h-42v171zM512 300h128v-43h-128v43zM683 471h42v-86h-42v86zM683 385h128
+v-42h-128v42zM768 343h43v-86h-43v86zM683 300h85v-43h-85v43zM725 471h86v-43h-86v43zM384 172h213v-43h-213v43zM341 44h299v-43h-299v43z" />
+    <glyph glyph-name="iocnqipaotu" unicode="&#xe62a;" 
+d="M619 492zM341 492q0 115 81.5 196t196 81t196 -81t81.5 -196t-81.5 -196t-196 -81t-196 81t-81.5 196zM235 108zM43 108q0 79 56 135.5t135.5 56.5t136 -56.5t56.5 -135.5t-56.5 -135.5t-136 -56.5t-135.5 56.5t-56 135.5zM725 44zM597 44q0 53 37.5 90.5t90.5 37.5
+t90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5z" />
+    <glyph glyph-name="iocnqiehuo" unicode="&#xe62b;" 
+d="M0 684h43v-768h-43v768zM0 684h1024v-43h-1024v43zM981 641h43v-725h-43v725zM0 -41h1024v-43h-1024v43zM128 513h43v-469h-43v469zM128 513h299v-42h-299v42zM384 513h43v-469h-43v469zM171 385h213v-42h-213v42zM171 257h213v-42h-213v42zM85 87h384v-43h-384v43z
+M512 471h427v-43h-427v43zM725 556h43v-341h-43v341zM768 215h43v-43h-43v43zM811 172h42v-43h-42v43zM853 129h43v-42h-43v42zM896 215h43v-171h-43v171zM853 385h43v-85h-43v85zM811 300h42v-85h-42v85zM725 172h43v-43h-43v43zM683 129h42v-42h-42v42zM640 87h43v-43h-43
+v43zM512 129h85v-42h-85v42zM597 215h86v-43h-86v43zM512 385h43v-170h-43v170zM512 385h171v-42h-171v42zM640 385h43v-170h-43v170zM555 257h128v-42h-128v42zM811 556h42v-43h-42v43zM853 513h43v-42h-43v42z" />
+    <glyph glyph-name="iocnditu" unicode="&#xe62c;" horiz-adv-x="1025" 
+d="M894 432v0l6 5q5 0 7 1l1.5 1t4 3t3.5 3q9 7 10 8t8 -5q3 8 5 8l2.5 2t5 5t3.5 5q0 3 0.5 12.5t1 17t1.5 7.5l20 3q7 4 14 12l3 3q3 6 8.5 19t5.5 14q4 4 4 18q0 4 6 8l1.5 0.5l1.5 0.5q2 1 4 4.5t2.5 7l0.5 3.5q-23 -10 -26 -12q-17 -10 -26 -13q-16 -5 -19 5
+q-2 3 -2.5 12t-1 11t-2.5 3.5t-4.5 3t-3.5 2.5l-3 2.5t-5 2.5q-24 3 -27 15q-1 4 -3 22.5t-5.5 34t-6.5 18.5q-12 8 -15 8q-7 0 -12 4l-4 3t-7.5 5t-7.5 2q-16 0 -25 -6l-8 -5q-12 -11 -10 -13q8 -5 8 -9q0 -2 -8 -12t-9 -12q-16 -32 -21 -36q-1 0 -3 -1.5t-5.5 -4
+t-5.5 -4.5q-1 0 -4 1.5l-9 4.5t-12 5l-3 -6t-6.5 -14t-4.5 -10q-7 -17 0 -19q2 -1 5 1.5t6 1.5q3 0 10.5 -1.5t10.5 -0.5q1 0 3 2q8 4 10 0q19 -26 11 -32q-3 -2 -12.5 0.5t-21.5 -2.5q-22 -11 -30 -20q-6 -7 -22 -11q-2 0 -8 -3.5t-11 -5.5t-8 -1q-2 1 -5 4t-6 4t-7 0
+q-4 -2 -6 -18t-5 -19q-4 -5 -17.5 -13t-18.5 -9q-2 0 -6.5 1t-6.5 0q-3 -2 -15 -4q-2 0 -10.5 -0.5t-13.5 -2.5q-2 -1 -9.5 -4.5t-11.5 -4.5t-8 0q-3 2 -12.5 5t-13.5 5q-32 18 -40 19q-4 1 -21 2t-22 2.5t-9.5 0.5t-9.5 1.5t-7 9.5t-2.5 16t-1 13.5t-2.5 4.5q-7 0 -14 7
+q-16 17 -28 17q-21 0 -16 16q1 4 3.5 11t4 12t0.5 9q-1 6 -7 16t-10 12t-9.5 8.5t-6.5 9.5q0 2 -0.5 5t-1 4.5l-0.5 1.5q-11 0 -14 -4l-19 -15q-9 -11 -9.5 -14.5t-4 -11.5t-5.5 -8q-1 0 -9.5 4t-15 6t-10.5 -2q-2 -3 -7 -14t-9.5 -19.5t-6.5 -9.5l-9.5 1t-16.5 0t-9 -7
+t0 -15t1 -12q-5 -22 -7 -22t-6.5 -4t-4.5 -6q0 -14 -8 -16q-4 0 -10.5 -2.5t-8 -3t-6 -1t-9 -1.5t-5.5 -2q-2 -2 -7 -2.5t-7 -3.5q-6 -14 -13 -15q-3 0 -5.5 3.5t-7.5 3.5q-4 0 -9.5 -3.5t-9.5 -6.5l-3 -4q-17 -16 -17 -19t4 -15q0 -1 4 -5t3 -6q0 -1 1.5 -9.5t-0.5 -10.5
+q-9 -10 -6 -13q1 -1 3 -1t3 -0.5t2 -2.5q0 -17 4 -22q2 -2 15 -8t14 -8q10 -27 10 -28t-1 -5t-1 -10v-18q-1 -1 -2.5 -5.5t-3 -7.5t-3 -3t-4 1.5t-2.5 -0.5v-30l6 -4.5t11 -10t6 -9.5q1 -12 7 -11q1 0 4 1t4.5 1h5.5q10 -4 13 -11q5 -8 13 -10l19 -21q2 -2 4.5 -6t4 -5.5
+t4.5 -4t7 -2.5q5 -1 16 0t13 0q8 -6 7 -8q-1 -3 -0.5 -7t2.5 -4q1 0 4 6l3 6l2 2t4 3t3 0q2 0 7 -3.5t8 -3.5q12 0 13 -2q1 0 4 -10.5t4 -11.5q2 -2 11.5 0t14.5 5q1 1 14.5 11t16.5 11q4 2 12 -1l4.5 -2l9 -4l4.5 -2q1 0 3.5 3t5.5 5.5t5 2.5q4 -1 8 -12t3 -21
+q-4 -30 -19 -47q-2 -3 -4 -4.5t-3 -2t-2 -1.5t-1.5 -2.5l-1.5 -4.5q-3 -13 0 -13q1 0 8.5 0.5t13 0.5t6.5 -1l-3.5 -5.5t-1.5 -7.5q0 -1 1.5 -3t2 -4.5t0.5 -5.5q-4 -22 -3 -23h3.5h3.5t3 -2l1.5 -3.5t3 -5.5t2.5 -2l16 6q0 -2 -1 -4q-4 -5 -3 -6l10 -4l2 6q-2 13 4 15
+l6 5.5t14 5.5q18 -1 24 2q4 2 8.5 5.5t8 6l3.5 2.5q1 0 5.5 -3t5.5 -3q16 0 17 -5q0 -4 -3 -8.5t-3 -5.5q1 -4 21 -18l4 -2l4 -1q1 0 1.5 0.5t1.5 0.5q4 3 7 1q4 -6 7 -6h5l4 -1q0 -1 -3.5 -4t-4.5 -5t0 -3q6 -4 6 -7v-4t0.5 -4.5t3.5 -0.5q3 0 4 2.5t1 4.5v2q-3 7 2 12
+q10 11 24 13q5 0 8 -0.5t6 0.5t7 3t4.5 4t3.5 3q4 1 5 -2t4 -3t5 2t3 2q3 -1 5.5 0t2.5 4q0 12 6 11q3 0 8 -2t9 -2q5 2 12 6.5t7 6.5l-1.5 2t-1.5 3t2 4l2.5 2.5t2 0.5h3.5l8 3q5 -3 11 7q1 3 2.5 6t1.5 4.5t0.5 3t1 1.5h1.5q3 -2 6 -1.5t3 3.5q0 1 -1 4.5t-1 5.5t2 2
+q1 1 3.5 -1t3.5 0v2v3t2 0q7 -2 7 -2.5t-1 7t0 8.5q8 14 4 17t-4.5 4.5t1.5 2.5q2 0 4.5 -2t3.5 0q1 0 3 2t3 4q0 2 4 5.5t4 7.5q0 7 2 12t5 3q1 0 3 -2q4 -4 7 2q2 3 -2 7t-2 6l5 6l-2 3l7 15l-6 4q-1 6 -5 6q-7 0 -7 8q0 2 2.5 1t4.5 -2t4 1q1 1 4 3.5t4.5 4.5t0.5 4
+t-4.5 6.5t-6.5 8.5t-2 6t6.5 -1.5t7.5 -0.5q2 2 -5 10t-7 10q0 19 -6 29q-3 6 -11.5 11.5t-7.5 10.5q1 7 6.5 16t10.5 11q18 6 18 9l1 9q2 3 5 3l6 -1t9 -1t4 2l-2 8l8 8q-1 5 -11 4q-2 0 -6.5 1.5t-9.5 1.5q-5 1 -14.5 -5t-13.5 -6t-6 3t-3 5v3q2 10 -4 10q-14 2 -15 11
+q0 4 0.5 7.5t1 6.5t1.5 3l12 -3l12 8q6 -9 12 -11q2 0 4 2.5t3 4.5l1 3q-1 0 -2.5 1t-4 3t-1.5 5q2 8 8 8q3 0 5 1.5t2 2.5l1 2q5 8 12 11q13 6 13 0l-1 -11l3 -6l-6 -5.5t-4 -8.5q5 -9 1 -11l-4 -1q-1 0 -2.5 -1t-4 -3.5t-0.5 -5.5q2 -2 5 0t6 6l3 4q10 11 19 13q2 0 8.5 2
+t8 2t6.5 -2l3 10q10 8 14 11q1 1 2 1.5t2 0.5q1 1 4 2t4 2q1 0 4.5 5t7.5 9t5 4q4 -2 7 -6q4 -3 7 -3q3 1 4 4t1 5v3v0v0zM520 -91q-8 0 -8.5 -0.5t-1.5 -3t-2 -4t-1 -2.5q-5 -3 -6 -5q-2 -9 0 -12q1 0 2.5 -3t3.5 -4.5t4 -1.5q1 1 6 2.5t8 1.5t6 1t5 2.5t1.5 2.5t-2.5 3
+t-1.5 3.5t3.5 4t3 3.5q3 3 6 5q2 1 2.5 3.5t-0.5 3.5q-1 4 -13 3q-2 -1 -5 -1.5l-6 -1t-4 -0.5v0v0zM753 30q0 1 -1 1.5t-4 1.5t-7 -1q-11 -3 -15 -17q-11 -28 -11 -29q3 -5 3 -8q-3 -12 0 -16q6 -8 8 -8q0 1 3.5 10t4.5 10q11 15 11 21v6v5t2 5q2 4 4 6.5t3 4t1 2.5l-2 6v0
+v0z" />
+    <glyph glyph-name="icontabdown" unicode="&#xe62d;" 
+d="M512 139q-18 0 -30 13l-192 191q-12 13 -12 30.5t12.5 30t30 12.5t30.5 -13l161 -161l161 161q13 13 30.5 13t30 -12.5t12.5 -30t-12 -30.5l-192 -191q-12 -13 -30 -13z" />
+    <glyph glyph-name="icontableft" unicode="&#xe62e;" 
+d="M374 277.5q0 17.5 12 30.5l191 191q13 13 30.5 13t30 -12.5t12.5 -30.5t-12 -30l-161 -161l161 -162q12 -12 12 -29.5t-12.5 -30t-30 -12.5t-30.5 12l-191 191q-12 13 -12 30.5z" />
+    <glyph glyph-name="icontabright" unicode="&#xe62f;" 
+d="M650 277.5q0 -17.5 -12 -30.5l-191 -191q-13 -12 -30.5 -12t-30 12.5t-12.5 30t12 29.5l161 162l-161 161q-12 12 -12 30t12.5 30.5t30 12.5t29.5 -13l192 -191q12 -13 12 -30.5z" />
+    <glyph glyph-name="icontabup" unicode="&#xe630;" 
+d="M512 416q18 0 30 -13l192 -191q12 -12 12 -30t-12.5 -30.5t-30 -12.5t-30.5 13l-161 161l-161 -161q-13 -13 -30.5 -13t-30 12.5t-12.5 30.5t12 30l192 191q12 13 30 13z" />
+    <glyph glyph-name="iconcardedit" unicode="&#xe631;" 
+d="M940 719q-26 27 -53 44.5t-46 24.5t-34.5 10t-23.5 2l-8 -1l-706 -706l-66 -311l311 66l706 706q4 4 -1 33q-12 65 -79 132zM295 -115l-106 -23q-18 34 -45 61t-61 45l23 106l31 31q6 0 17.5 -2t44 -18.5t61.5 -45.5t45.5 -60t18.5 -47l2 -16z" />
+    <glyph glyph-name="iconcardshare" unicode="&#xe632;" 
+d="M449 245h126v315h189l-252 252l-252 -252h189v-315zM638 371v-97l289 -108l-415 -155l-415 155l289 108v97l-378 -142v-252l504 -189l504 189v252z" />
+    <glyph glyph-name="iconxiaoyuhao" unicode="&#xe633;" 
+d="M725 51v-50l-426 258v43l426 254v-53l-389 -223z" />
+    <glyph glyph-name="iconxiaoyudengyuhao" unicode="&#xe636;" 
+d="M725 241v-53l-426 158v52l426 158v-49l-372 -135zM725 87v-43l-426 154v49z" />
+    <glyph glyph-name="iconxiaoyuhaodaijiantou1" unicode="&#xe637;" 
+d="M469 167v-50l-426 258v43l426 254v-53l-389 -223zM982 75l-171 -171l-172 171h343z" />
+    <glyph glyph-name="iconxiaoyudengyudaijiantou1" unicode="&#xe638;" 
+d="M469 314v-52l-426 157v53l426 157v-49l-372 -134zM469 160v-43l-426 155v49zM983 75l-172 -171l-171 171h343z" />
+    <glyph glyph-name="bi40qietubianjixiangqing" unicode="&#xe634;" 
+d="M860 748q41 0 70.5 -29.5t29.5 -70.5q0 -33 -20 -60l-40 -40l-140 140l40 40q27 20 60 20zM360 288l-40 -180l180 40l370 370l-140 140zM767 521l-280 -280l-34 34l280 280zM832 172v-192h-640v640h192l128 128h-320q-53 0 -90.5 -37.5t-37.5 -90.5v-640
+q0 -53 37.5 -90.5t90.5 -37.5h640q53 0 90.5 37.5t37.5 90.5v320z" />
+    <glyph glyph-name="bi40qietudaochuexcel" unicode="&#xe635;" 
+d="M974 176q21 -16 21 -39.5t-21 -40.5l-220 -176q-21 -16 -35.5 -9t-14.5 33v100h-257q-26 0 -44.5 18.5t-18.5 45.5q0 26 18.5 45t44.5 19h257v157q0 26 14.5 33t35.5 -10zM192 -20v640h384v-192h64h128h128v64l-256 256h-512q-18 0 -31 -7t-19 -16.5t-9.5 -19t-4.5 -16.5
+v-7v-766q0 -28 16 -44t32 -18l16 -2h512v128h-448zM640 684l192 -192h-192v192z" />
+    <glyph glyph-name="bi40qietufuzhi" unicode="&#xe639;" 
+d="M64 620h64v-768h-64v768zM64 -84h704v-64h-704v64zM704 748h-448q-18 0 -31 -7t-19 -16.5t-9.5 -19t-4.5 -16.5v-7v-638q0 -28 16 -44t32 -18l16 -2h576q28 0 44 16t18 32l2 16v512zM768 108h-448v64h448v-64zM768 236h-448v64h448v-64zM768 364h-448v64h448v-64z
+M704 556v128l128 -128h-128z" />
+    <glyph glyph-name="bi40qietujiangxu" unicode="&#xe63a;" 
+d="M64 44h384v-128h-384v128zM64 364h640v-128h-640v128zM64 684h896v-128h-896v128z" />
+    <glyph glyph-name="bi40qietuketuozhuai" unicode="&#xe63b;" 
+d="M64 620h896v-128h-896v128zM64 364h896v-128h-896v128zM64 108h896v-128h-896v128z" />
+    <glyph glyph-name="bi40qietuliandong" unicode="&#xe63c;" 
+d="M704 492h-297l110 -112l-197 -203l68 -69l202 202l114 -112v294zM896 748h-768q-26 0 -45 -19t-19 -45v-768q0 -26 19 -45t45 -19h768q26 0 45 19t19 45v768q0 26 -19 45t-45 19zM832 -20h-640v640h640v-640z" />
+    <glyph glyph-name="bi40qietuqingkong" unicode="&#xe63d;" horiz-adv-x="1029" 
+d="M1029 321l-390 390l-634 -634l161 -161h26h72h262h98h16v16zM200 -20l-98 97l293 293l292 -293l-97 -97h-390z" />
+    <glyph glyph-name="bi40qietushanchu" unicode="&#xe63e;" 
+d="M576 684v64h-192v-64h-256v-128h704v128h-256zM192 -20q0 -53 37.5 -90.5t90.5 -37.5h320q53 0 90.5 37.5t37.5 90.5v512h-576v-512zM576 428h64v-448h-64v448zM448 428h64v-448h-64v448zM320 428h64v-448h-64v448z" />
+    <glyph glyph-name="bi40qietushengxu" unicode="&#xe63f;" 
+d="M64 684h384v-128h-384v128zM64 364h640v-128h-640v128zM64 44h896v-128h-896v128z" />
+    <glyph glyph-name="bi40qietushijian" unicode="&#xe640;" 
+d="M480 684q-172 0 -294 -122t-122 -294t122 -294t294 -122t294 122t122 294t-122 294t-294 122zM480 -84q-146 0 -249 103t-103 249t103 249t249 103t249 -103t103 -249t-103 -249t-249 -103zM448 492h64v-256h-64v256zM448 300h384v-64h-384v64z" />
+    <glyph glyph-name="bi40qietushuzi" unicode="&#xe641;" 
+d="M128 556q-3 0 -7 -0.5t-15 -4t-19.5 -9.5t-15.5 -19t-7 -31v-64h64v-448h64v0v576v0h-64zM448 44h-64l192 256h-64l-192 -256q0 -3 0.5 -7t4 -15t9.5 -19.5t19 -15.5t31 -7h192v64h-128zM512 556h-128q-3 0 -7 -0.5t-15 -4t-19.5 -9.5t-15.5 -19t-7 -31v-128h64v128h64
+h64v-192h64v192q0 3 -0.5 7t-4 15t-9.5 19.5t-19 15.5t-31 7zM832 556h-64q-3 0 -7 -0.5t-15 -4t-19.5 -9.5t-15.5 -19t-7 -31v-128h64v128h64h64v-192h-128v-64h128v-192h-64h-64v128h-64v-128q0 -28 16 -44t32 -18l16 -2h64h128v576h-128z" />
+    <glyph glyph-name="bi40qietuwenzi" unicode="&#xe642;" 
+d="M256 620h-128q-26 0 -45 -19t-19 -45v-512h64v256h128v-256h64v512q0 26 -19 45t-45 19zM256 364h-128v192h128v-192zM960 556v64h-192q-26 0 -45 -19t-19 -45v-448q0 -26 19 -45t45 -19h192v64h-192v448h192zM640 396v160q0 26 -19 45t-45 19h-192v-576h192q26 0 45 19
+t19 45v160q0 64 -44 64q44 0 44 64zM576 108h-128v192h128v-192zM576 364h-128v192h128v-192z" />
+    <glyph glyph-name="bi40qietuzhongmingming" unicode="&#xe687;" 
+d="M512 684q159 0 271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5zM512 748q-122 0 -225 -60t-163 -163t-60 -225t60 -225t163 -163t225 -60t225 60t163 163t60 225t-60 225t-163 163t-225 60v0zM384 556h256
+v-64h-256v64zM384 108h256v-64h-256v64zM448 492h128v-384h-128v384z" />
+    <glyph glyph-name="iconriqikongjian" unicode="&#xe646;" 
+d="M64 556h832v-704h-832v704zM832 812v-64h-128v64h-448v-64h-128v64h-128v-1024h960v1024h-128zM128 236h128v-128h-128v128zM704 236h128v-128h-128v128zM512 236h128v-128h-128v128zM320 236h128v-128h-128v128zM512 44h128v-128h-128v128zM320 44h128v-128h-128v128z
+M128 44h128v-128h-128v128zM704 428h128v-128h-128v128zM512 428h128v-128h-128v128zM320 428h128v-128h-128v128z" />
+    <glyph glyph-name="icontianjia" unicode="&#xe649;" 
+d="M960 364h-384v384h-128v-384h-384v-128h384v-384h128v384h384v128z" />
+    <glyph glyph-name="iconwenjianjia" unicode="&#xe64a;" 
+d="M0 492h1024l-64 -640h-896zM928 620l32 -64h-896l64 128h352l32 -64h416z" />
+    <glyph glyph-name="iconxuanzhong" unicode="&#xe64c;" 
+d="M896 556l-64 64l-448 -320l-192 128l-64 -64l256 -320z" />
+    <glyph glyph-name="iconjiacu" unicode="&#xe64d;" 
+d="M632 355q40 46 40 105q0 66 -47 113t-113 47h-256v-64h64v-512h-64v-64h320q80 0 136 56t56 136q0 64 -38 114.5t-98 68.5zM512 556q40 0 68 -28t28 -68t-28 -68t-68 -28h-64v192h64zM576 44h-128v256h128q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5z" />
+    <glyph glyph-name="iconjingshi" unicode="&#xe64e;" 
+d="M948 -53l-383 762q-22 39 -53 39t-53 -39l-383 -762q-22 -39 -5.5 -67t61.5 -28h760q45 0 61.5 28t-5.5 67zM576 -20h-128v128h128v-128zM576 172h-128v256h128v-256z" />
+    <glyph glyph-name="iconjuzhongduiqi" unicode="&#xe64f;" 
+d="M384 620h320v-64h-320v64zM192 428h704v-64h-704v64zM384 236h320v-64h-320v64zM192 44h704v-64h-704v64z" />
+    <glyph glyph-name="iconxiahuaxian" unicode="&#xe650;" 
+d="M576 620v-384q0 -26 -28 -45t-68 -19t-68 19t-28 45v384h-128v-384q0 -62 65.5 -105.5t158.5 -43.5t158.5 43.5t65.5 105.5v384h-128zM192 44h576v-64h-576v64z" />
+    <glyph glyph-name="iconyouduiqi" unicode="&#xe651;" 
+d="M576 620h320v-64h-320v64zM192 428h704v-64h-704v64zM576 236h320v-64h-320v64zM192 44h704v-64h-704v64z" />
+    <glyph glyph-name="iconzitibeijing" unicode="&#xe652;" 
+d="M371 44l44 147l33 33v12v64v64h-64v64h-256v-64h192v-64h-128h-64v-64h-64v-128h64v-64h64h128h51zM192 236h128v-128h-128v128zM652 428h-12v192h-128v-332zM768 152v-44h-44l-64 -64h172v64h64v172zM887 381l-303 -302l-136 -35l45 125l303 303zM64 -20h896v-128h-896
+v128z" />
+    <glyph glyph-name="iconzitiyanse" unicode="&#xe653;" 
+d="M867 44h-174l-45 128h-241l-46 -128h-169l241 640h193zM607 300l-80 233l-80 -233h160zM64 -20h896v-128h-896v128z" />
+    <glyph glyph-name="iconzuoduiqi" unicode="&#xe654;" 
+d="M192 620h320v-64h-320v64zM192 428h704v-64h-704v64zM192 236h320v-64h-320v64zM192 44h704v-64h-704v64z" />
+    <glyph glyph-name="iconurl" unicode="&#xe655;" 
+d="M384 748h154q114 0 169.5 -62.5t55.5 -190.5q0 -169 -110 -230l137 -413h-135l-118 384h-25v-384h-128v896zM512 364h21q63 0 82.5 28.5t19.5 99.5q0 72 -20.5 100t-87.5 28h-15v-256zM832 748h128v-768h64v-128h-192v896zM192 748v-768h-64v768h-128v-704q0 -84 42 -138
+t118 -54t118 54t42 138v704h-128z" />
+    <glyph glyph-name="iconxieti" unicode="&#xe656;" 
+d="M384 620v-64h128l-128 -512h-128v-64h384v64h-128l128 512h128v64h-384z" />
+    <glyph glyph-name="iconwenzi" unicode="&#xe657;" 
+d="M832 -148h128l-398 896h-98l-400 -896h128q49 115 108 256h424zM354 236q152 361 158 384q10 -31 158 -384h-316z" />
+    <glyph glyph-name="iconanshijianpaixu" unicode="&#xe658;" 
+d="M512 748q-122 0 -225 -60t-163 -163t-60 -225t60 -225t163 -163t225 -60t225 60t163 163t60 225t-60 225t-163 163t-225 60zM512 -36q-139 0 -237.5 98.5t-98.5 237.5t98.5 237.5t237.5 98.5t237.5 -98.5t98.5 -237.5t-98.5 -237.5t-237.5 -98.5zM576 492h-128v-215
+l188 -185l86 80l-146 151v169z" />
+    <glyph glyph-name="iconanzimupaixu" unicode="&#xe659;" 
+d="M64 172h320l-320 -192v-128h448v128h-320l320 192v128h-448v-128zM192 748h-64h-64v-384h128v64h192v-64h128v256v128h-128h-192zM384 556h-192v64h192v-64zM832 108v640h-128v-640h-128l192 -256l192 256h-128z" />
+    <glyph glyph-name="iconfenxianggei" unicode="&#xe65a;" 
+d="M768 236q-52 0 -96 -26.5t-70 -70.5l-166 96q12 34 12 65q0 25 -9 55l168 97q26 -41 68.5 -64.5t92.5 -23.5q80 0 136 56t56 136t-56 136t-136 56t-136 -56t-56 -136q0 -20 6 -45l-171 -98q-27 36 -67.5 57.5t-87.5 21.5q-80 0 -136 -56t-56 -136t56 -136t136 -56
+q44 0 82.5 19t65.5 53l175 -101q-3 -20 -3 -35q0 -80 56 -136t136 -56t136 56t56 136t-56 136t-136 56zM768 652q40 0 68 -28t28 -68t-28 -68t-68 -28t-68 28t-28 68t28 68t68 28zM256 204q-40 0 -68 28t-28 68t28 68t68 28t68 -28t28 -68t-28 -68t-68 -28zM768 -52
+q-40 0 -68 28t-28 68t28 68t68 28t68 -28t28 -68t-28 -68t-68 -28z" />
+    <glyph glyph-name="iconwenjian" unicode="&#xe65b;" 
+d="M640 748h-512q-18 0 -31 -7t-19 -16.5t-9.5 -19t-4.5 -16.5v-7v-766q0 -28 16 -44t32 -18l16 -2h704q28 0 44 16t18 32l2 16v576zM768 44h-576v64h576v-64zM768 172h-576v64h576v-64zM768 300h-576v64h576v-64zM640 492v192l192 -192h-192z" />
+    <glyph glyph-name="iconwenjianjia1" unicode="&#xe65c;" 
+d="M928 684h-416l-32 64h-352l-64 -128h896zM0 556l64 -640h896l64 640h-1024z" />
+    <glyph glyph-name="iconxinjianwenjianjia" unicode="&#xe65d;" 
+d="M640 620l-128 128h-448v-128v-768h896v768h-320zM832 -20h-640v512h640v-512zM448 44h128v128h128v128h-128v128h-128v-128h-128v-128h128v-128z" />
+    <glyph glyph-name="iconyidongdao" unicode="&#xe65e;" 
+d="M672 620l-128 128h-480v-128v-768h896v768h-288zM832 -20h-640v512h640v-512zM576 76l192 192l-192 192v-160h-320v-128h320v-96z" />
+    <glyph glyph-name="iconyulan" unicode="&#xe65f;" 
+d="M512 620q-165 0 -302 -87.5t-210 -232.5q73 -145 210 -232.5t302 -87.5t302 87.5t210 232.5q-73 145 -210 232.5t-302 87.5zM416 498q40 0 68 -28t28 -68t-28 -68t-68 -28t-68 28t-28 68t28 68t68 28zM764 150q-115 -74 -252 -74t-252 74q-92 58 -150 150q58 92 150 150
+q5 4 11 8q-15 -43 -15 -88q0 -106 75 -181t181 -75t181 75t75 181q0 45 -15 88q8 -5 11 -8q92 -58 150 -150q-58 -92 -150 -150z" />
+    <glyph glyph-name="iconbianliang" unicode="&#xe660;" 
+d="M384 364h64v128h128v-128h64v128h192v64h-256v64h-128v-64h-256v-64h192v-128zM256 428h64v-64h-64v64zM192 364h64v-64h-64v64zM704 428h64v-64h-64v64zM768 364h64v-64h-64v64zM576 236v-64h128v64h64v64h-512v-64h64v-64h128v64h128zM576 108v64h-64h-64v-64h64h64z
+M320 108h128v-64h-128v64zM576 108h128v-64h-128v64zM192 44h128v-64h-128v64zM704 44h128v-64h-128v64zM64 748v-896h896v896h-896zM896 -84h-768v768h768v-768z" />
+    <glyph glyph-name="icontuozhuaishangxia" unicode="&#xe661;" 
+d="M512 236h-64v-192h-192l224 -192l224 192h-192v192zM448 428h64v192h192l-224 192l-224 -192h192v-192zM192 364h576v-64h-576v64z" />
+    <glyph glyph-name="icontuozhuaiyouxie" unicode="&#xe662;" 
+d="M471 386l-226 226l136 136h-317v-317l136 136l226 -226zM366 190l256 256l45 -45l-256 -256zM823 35l-216 215l-45 -45l215 -216l-137 -137h320v320z" />
+    <glyph glyph-name="icontuozhuaizuoxie" unicode="&#xe663;" 
+d="M353 314l-216 -215l-137 137v-320h320l-137 137l215 216zM548 209l-256 256l46 45l256 -256zM579 812l136 -136l-226 -226l45 -45l226 226l136 -136v317h-317z" />
+    <glyph glyph-name="icontuozhuaizuoyou" unicode="&#xe664;" 
+d="M960 257l-192 224v-181h-192v-64h192v-203zM192 481l-192 -224l192 -224v203h192v64h-192v181zM448 556h64v-576h-64v576z" />
+    <glyph glyph-name="icontuozhuai" unicode="&#xe665;" 
+d="M960 332l-192 224v-192h-128h-64h-64v256h-64v-256h-256v192l-192 -224l192 -224v192h256v-64v0v-192h-192l224 -192l224 192h-192v192v0v64h64h64h128v-192zM480 812l-224 -192h448z" />
+    <glyph glyph-name="iconjiangxuwuguolv" unicode="&#xe666;" 
+d="M728 236h-152v404q0 15 -10 29.5t-23 14.5h-62q-13 0 -23 -14.5t-10 -29.5v-404h-152q-12 0 -17.5 -14t2.5 -23l216 -273q6 -7 15 -7.5t15 6.5l216 275q8 9 2.5 22.5t-17.5 13.5z" />
+    <glyph glyph-name="iconjiangxuyouguolv" unicode="&#xe667;" 
+d="M448 684l192 -320v-448l128 128v320l192 320h-512zM491 172h-107v404q0 15 -10 29.5t-23 14.5h-62q-13 0 -23 -14.5t-10 -29.5v-404h-107q-10 0 -14 -11t2 -19l171 -219q5 -5 12 -4.5t12 6.5l171 217q6 7 2 18.5t-14 11.5z" />
+    <glyph glyph-name="iconshengxuwuguolv" unicode="&#xe668;" 
+d="M281 395l216 270q6 7 15 7t15 -7l216 -270q8 -9 2.5 -20t-17.5 -11h-432q-12 0 -17.5 11t2.5 20zM543 -84h-62q-14 0 -23.5 9.5t-9.5 23.5v415h128v-415q0 -14 -9.5 -23.5t-23.5 -9.5z" />
+    <glyph glyph-name="iconshengxuyouguolv" unicode="&#xe669;" 
+d="M448 684l192 -320v-448l128 128v320l192 320h-512zM332 603q-5 5 -12 5t-12 -5l-171 -214q-6 -8 -2 -16.5t14 -8.5h107v-415q0 -14 9.5 -23.5t23.5 -9.5h62q14 0 23.5 9.5t9.5 23.5v415h107q10 0 14 8.5t-2 16.5z" />
+    <glyph glyph-name="iconwupaixuwuguolv" unicode="&#xe66a;" 
+d="M256 428l256 -320l256 320h-512z" />
+    <glyph glyph-name="iconwupaixuyouguolv" unicode="&#xe66b;" 
+d="M128 684l320 -384v-384l128 128v256l320 384h-768z" />
+    <glyph glyph-name="iconbupaixu" unicode="&#xe66c;" 
+d="M384 236v11l-128 128v-139h-152q-12 0 -17.5 -13.5t2.5 -22.5l216 -275q6 -7 15 -6.5t15 7.5l163 207l-103 103h-11zM935 395l-216 270q-6 7 -15 7t-15 -7l-161 -200l101 -101h11v-11l128 -128v139h152q12 0 17.5 11t-2.5 20zM263 639q-19 19 -45.5 19t-45 -18.5
+t-18.5 -45t19 -45.5l588 -588q19 -19 45.5 -19t45 18.5t18.5 45t-19 45.5z" />
+    <glyph glyph-name="iconzidingyipaixu" unicode="&#xe66f;" 
+d="M935 395l-216 270q-6 7 -15 7t-15 -7l-216 -270q-8 -9 -2.5 -20t17.5 -11h432q12 0 17.5 11t-2.5 20zM673 -84h62q14 0 23.5 9.5t9.5 23.5v415h-128v-415q0 -14 9.5 -23.5t23.5 -9.5zM551 199l-216 -273q-6 -7 -15 -7.5t-15 6.5l-216 275q-8 9 -2.5 22.5t17.5 13.5h432
+q12 0 17.5 -14t-2.5 -23zM300 684h51q14 0 23.5 -9.5t9.5 -23.5v-415h-128v404q0 18 13 31t31 13z" />
+    <glyph glyph-name="iconyewubao" unicode="&#xe644;" 
+d="M928 684h-416l-32 64h-352l-64 -128h896zM0 556l64 -640h896l64 640h-1024z" />
+    <glyph glyph-name="iconmobanshaixuandianjishouqi" unicode="&#xe645;" 
+d="M480 492l-256 -256l64 -64l192 213l192 -213l64 64zM480 812q-98 0 -186.5 -38t-153 -102.5t-102.5 -153t-38 -186.5t38 -186.5t102.5 -153t153 -102.5t186.5 -38t186.5 38t153 102.5t102.5 153t38 186.5t-38 186.5t-102.5 153t-153 102.5t-186.5 38zM480 -88
+q-114 0 -210.5 56.5t-153 153t-56.5 210.5t56.5 210.5t153 153t210.5 56.5t210.5 -56.5t153 -153t56.5 -210.5t-56.5 -210.5t-153 -153t-210.5 -56.5z" />
+    <glyph glyph-name="iconmobanshaixuandianjizhankai" unicode="&#xe648;" 
+d="M480 172l-256 256l64 64l192 -213l192 213l64 -64zM960 332q0 98 -38 186.5t-102.5 153t-153 102.5t-186.5 38t-186.5 -38t-153 -102.5t-102.5 -153t-38 -186.5t38 -186.5t102.5 -153t153 -102.5t186.5 -38t186.5 38t153 102.5t102.5 153t38 186.5zM900 332
+q0 -114 -56.5 -210.5t-153 -153t-210.5 -56.5t-210.5 56.5t-153 153t-56.5 210.5t56.5 210.5t153 153t210.5 56.5t210.5 -56.5t153 -153t56.5 -210.5z" />
+    <glyph glyph-name="iconquxiaoguachushenqing" unicode="&#xe64b;" 
+d="M819 748h-614q-13 0 -13 -7v-876q0 -7 5 -7q2 0 5 2l310 185l310 -185q3 -2 5 -2q5 0 5 7v876q0 7 -13 7v0z" />
+    <glyph glyph-name="iconshenqingguachu" unicode="&#xe66d;" 
+d="M819 748h-614q-13 0 -13 -7v-876q0 -7 5 -7q2 0 5 2l310 185l310 -185q3 -2 5 -2q5 0 5 7v876q0 7 -13 7zM768 -33l-223 133l-33 20l-33 -20l-223 -133v717h512v-717zM435 364q5 0 9 -4t4 -9v-166q0 -5 4 -9t9 -4h102q5 0 9 4t4 9v166q0 5 4 9t9 4h102q5 0 6.5 3t-1.5 7
+l-181 236q-8 10 -15 0l-172 -236q-4 -4 -2 -7t7 -3h102z" />
+    <glyph glyph-name="iconxiangqing" unicode="&#xe66e;" 
+d="M512 684q159 0 271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5zM512 748q-122 0 -225 -60t-163 -163t-60 -225t60 -225t163 -163t225 -60t225 60t163 163t60 225t-60 225t-163 163t-225 60v0zM448 364h128
+v-320h-128v320zM448 556h128v-128h-128v128z" />
+    <glyph glyph-name="iconzhongmingming" unicode="&#xe670;" 
+d="M722 748q46 0 78 -32t32 -78q0 -37 -22 -66l-44 -44l-154 154l44 44q29 22 66 22zM172 242l-44 -198l198 44l407 407l-154 154zM620 498l-308 -308l-38 38l308 308zM64 -20h896v-128h-896v128z" />
+    <glyph glyph-name="iconbaiduditu" unicode="&#xe643;" 
+d="M606 118q47 10 39 77q-2 17 -18 34t-36 15q-17 -1 -27.5 -15.5t-13.5 -28.5l-2 -13q-5 -24 11 -50t47 -19zM656 21q-5 -13 -2 -22q5 -19 22 -20h24v59h-26q-14 -4 -18 -17zM692.5 211q19.5 0 33 19t13.5 46.5t-13.5 47t-33 19.5t-33 -19.5t-13.5 -47t13.5 -46.5t33 -19z
+M803 206q23 -3 40 16.5t20 43.5q4 21 -9.5 41t-31.5 25q-18 4 -37 -17.5t-21 -41.5q-6 -61 39 -67zM887 44q-53 41 -84 85q-20 30 -45.5 37t-45.5 -3t-31 -29q-8 -14 -21 -27.5t-23 -22t-11 -9.5q0 -1 -8 -7t-15.5 -13t-16 -19t-11 -25.5t-0.5 -32.5q6 -26 21 -40t27 -16.5
+t12 -0.5q34 -4 74 5q20 4 36.5 3.5t27.5 -2.5l10 -3q4 -1 10 -3t23.5 -4t32 -0.5t30 10.5t22.5 26q23 54 -12 88zM728 -45h-60q-12 2 -21 8t-12.5 10.5t-4.5 7.5q-8 19 -5 41q5 16 16 26t19 12l9 1h32v40l27 -1v-145zM840 -45h-69q-12 3 -19 10t-8 10.5t-1 5.5v77h28v-69
+q2 -7 11 -8v0h28v77h30v-103zM938 160q0 16 -12.5 34.5t-38.5 18.5q-47 0 -47 -64q0 -13 1.5 -21t6 -18.5t16 -15.5t29.5 -5q8 0 15 2t11.5 6t8 8t5.5 10t3.5 10t1.5 11t0.5 10t0 8.5zM465 74q6 -14 19 -22t28 -8t28 8t20 22l3 7q-20 8 -34 25q-15 19 -21 43t-2 44
+q3 32 23 61t58 33h7q5 0 10 -1q3 43 28 71t60 28q4 0 14 -1l6 12q13 29 13 75q0 88 -62.5 150.5t-150.5 62.5t-150.5 -62.5t-62.5 -150.5q0 -46 13 -75zM436.5 546q31.5 31 75.5 31t75.5 -31t31.5 -75t-31.5 -75.5t-75.5 -31.5t-75.5 31.5t-31.5 75.5t31.5 75zM559 -84h-474
+l171 256h115l20 -43h-112l-114 -170h372q8 -26 22 -43z" />
+    <glyph glyph-name="iconbiaogeleixinghengxiangzhankai" unicode="&#xe671;" 
+d="M43 684v-768h938v768h-938zM939 -41h-854v682h854v-682zM341 1h-213v598h213v-598zM597 215h-213v384h213v-384zM597 1h-213v171h213v-171zM896 428h-256v171h256v-171zM896 215h-256v170h256v-170zM896 1h-256v171h256v-171z" />
+    <glyph glyph-name="iconbiaogeleixingzongxiangzhankai" unicode="&#xe672;" 
+d="M43 684v-768h938v768h-938zM939 -41h-854v682h854v-682zM128 599v-171h768v171h-768zM277 471l-64 85h128zM128 385v-170h768v170h-768zM491 257l-64 86h128zM128 172v-171h768v171h-768zM704 44l-64 85h128z" />
+    <glyph glyph-name="icongugeditu" unicode="&#xe673;" 
+d="M692 267q0 -60 40 -86q24 -16 59 -16q4 0 7 1q-4 -27 16 -54h-1q-14 0 -28.5 -1t-37 -7t-39.5 -16t-29 -29.5t-12 -45.5t11 -46t26 -29.5t34.5 -15t30.5 -6.5t21 -1h3v0h4q44 0 79 17q63 30 63 103q0 22 -10.5 42t-19.5 29.5t-26 24.5q-26 23 -26 33.5t20 28.5
+q36 32 36 84q0 33 -7 51.5t-29 30.5q2 1 20 3q42 6 42 19v3h-123q-3 0 -13.5 -1.5t-30.5 -8t-37 -17.5t-30 -35t-13 -55zM890 26q2 -28 -20 -47t-58 -21q-37 -3 -63.5 12.5t-27.5 43.5q-2 28 22 49q24 22 61 25h8q33 0 54.5 -17.5t23.5 -44.5zM858 292q9 -31 -2 -59.5
+t-33 -34.5q-5 -2 -10 -2q-20 0 -38 18t-25 46q-8 31 1 56q10 27 31 33q5 2 11 2q25 0 40.5 -13t24.5 -46zM465 74q6 -14 19 -22t28 -8t28 8t20 22l81 173q-1 12 -1 20q0 91 74 137q11 29 11 67q0 88 -62.5 150.5t-150.5 62.5t-150.5 -62.5t-62.5 -150.5q0 -46 13 -75z
+M436.5 546q31.5 31 75.5 31t75.5 -31t31.5 -75t-31.5 -75.5t-75.5 -31.5t-75.5 31.5t-31.5 75.5t31.5 75zM633 129l20 43h15q13 -18 31 -31q-10 -5 -21 -12h-45zM652 -84h-567l171 256h115l20 -43h-112l-114 -170h460q10 -25 27 -43z" />
+    <glyph glyph-name="iconloudoutu" unicode="&#xe674;" 
+d="M853 343h-682l-86 256h854zM768 129h-512l-85 171h682zM768 87h-512l85 -128h342z" />
+    <glyph glyph-name="iconxuansejiantoubai" unicode="&#xe675;" horiz-adv-x="1280" 
+d="M128 684l512 -768l512 768h-1024z" />
+    <glyph glyph-name="iconxuansejiantouhei" unicode="&#xe676;" 
+d="M884 719l-744 -419l744 -419v838z" />
+    <glyph glyph-name="icongisditu" unicode="&#xe677;" 
+d="M725 513q0 -45 -13 -74l-152 -323q-7 -13 -20 -21t-28 -8t-28 7.5t-19 21.5l-153 323q-13 29 -13 74q0 89 62.5 151.5t150.5 62.5t150.5 -62.5t62.5 -151.5zM587.5 438q31.5 31 31.5 75t-31.5 75.5t-75.5 31.5t-75.5 -31.5t-31.5 -75.5t31.5 -75t75.5 -31t75.5 31z
+M768 215h-115l-20 -43h112l114 -171h-694l114 171h112l-20 43h-115l-171 -256h854z" />
+    <glyph glyph-name="iconshezhi" unicode="&#xe678;" 
+d="M504 494q-81 0 -138.5 -57.5t-57.5 -139t57.5 -139t138.5 -57.5t138.5 57.5t57.5 139t-57.5 139t-138.5 57.5v0v0v0zM504 154q-60 0 -102 42t-42 101.5t42 101.5t101.5 42t102 -42t42.5 -101.5t-42.5 -101.5t-101.5 -42v0v0v0zM936 390q-22 2 -51 13.5t-39 32.5
+q-15 34 29 96l12 17l-122 129l-19 -14q-20 -15 -51 -27.5t-52 -2.5q-30 14 -33 89l-1 25h-97h-97l-1 -25q-3 -75 -33 -89q-21 -10 -52 2.5t-51 27.5l-19 14l-123 -129l13 -17q44 -62 28 -96q-9 -21 -37.5 -32.5t-51.5 -13.5l-24 -2v-79v0v-96l24 -2q23 -3 51.5 -14t38.5 -32
+q15 -34 -29 -96l-12 -18l122 -129l19 14q20 15 51 27.5t52 3.5q30 -15 33 -89l1 -26h97h97l1 26q3 74 33 89q21 9 52 -3.5t51 -27.5l19 -14l122 129l-12 18q-44 62 -29 96q10 21 39 32.5t51 13.5l24 2v95v0v80l-24 2v0v0v0zM908 309v0v-50q-84 -18 -109 -73t21 -130l-62 -65
+q-81 49 -137 23q-52 -25 -61 -109h-48h-48q-9 84 -61 109q-56 26 -137 -23l-62 65q46 75 21 130t-109 73v49v0v33q84 18 109 73t-21 130l62 65q81 -49 137 -22q52 24 61 109h48h48q9 -85 61 -109q56 -27 137 22l62 -65q-46 -75 -21 -130t109 -73v-32v0v0v0v0zM908 309z" />
+    <glyph glyph-name="iconziduanguanlianshezhi" unicode="&#xe647;" 
+d="M914 506l-455 -451q-57 -55 -137 -55t-137 55.5t-57 135t57 135.5l410 405q38 37 91.5 37t91.5 -37t38 -90t-38 -90l-411 -405q-18 -19 -45 -19t-46 18.5t-19 45t19 45.5l365 360l-46 45l-364 -360q-38 -38 -38 -90.5t37.5 -90t91 -37.5t91.5 37l410 406q57 56 57 135
+t-56.5 135t-137 56t-136.5 -56l-433 -428l1 -1q-59 -75 -53.5 -171.5t75 -165t167 -74t173.5 53.5l1 -2l479 473l-46 45v0v0zM914 506z" />
+    <glyph glyph-name="suoding" unicode="&#xe679;" 
+d="M805 457v293q0 30 -21.5 51.5t-52.5 21.5h-438q-31 0 -52.5 -21.5t-21.5 -51.5v-293h-73v-512h732v512h-73zM366 457v220h292v-220h-292z" />
+    <glyph glyph-name="guolv" unicode="&#xe67a;" 
+d="M128 768l320 -384v-384l128 128v256l320 384h-768z" />
+    <glyph glyph-name="iconbiaoge" unicode="&#xe67b;" 
+d="M896 832h-768q-26 0 -45 -19t-19 -45v-768q0 -26 19 -45t45 -19h768q26 0 45 19t19 45v768q0 26 -19 45t-45 19zM384 384v128h256v-128h-256zM640 320v-128h-256v128h256zM128 512h192v-128h-192v128zM128 320h192v-128h-192v128zM128 0v128h192v-128h-192zM384 0v128
+h256v-128h-256zM896 0h-192v128h192v-128zM896 192h-192v128h192v-128zM896 384h-192v128h192v-128z" />
+    <glyph glyph-name="iconloudoutu1" unicode="&#xe67c;" 
+d="M85 768l43 -213h768l43 213h-854zM213 256h598l85 256h-768zM341 0h342l128 213h-598z" />
+    <glyph glyph-name="iconyaochi" unicode="&#xe67d;" 
+d="M672 832q-119 0 -203.5 -84.5t-84.5 -203.5q0 -42 15 -89l-335 -391v-72q0 -23 16.5 -39.5t39.5 -16.5h72v64h128v128h128v128h64l31 31q63 -31 129 -31q119 0 203.5 84.5t84.5 203.5t-84.5 203.5t-203.5 84.5zM672 384q-66 0 -113 47t-47 113t47 113t113 47t113 -47
+t47 -113t-47 -113t-113 -47v0z" />
+    <glyph glyph-name="icongis" unicode="&#xe67e;" 
+d="M341 555h43v-43h-43v43zM128 256h43v-43h128h42h43v128v43h-128v-43h43v-85h-86v43h-42v213h42v43h128v42h-170v-42h-43v-43h-43v-213h43v-43zM597 256h-42v299h42v42h-170v-42h42v-299h-42v-43h170v43zM853 555h43v-43h-43v43zM853 213v43h43v85v43h-43v43h-85v42h-43
+v86h128v42h-170v-42h-43v-128h43v-43h85v-43h43v-85h-128v-43h170zM640 299h43v-43h-43v43zM0 768v-725h981v725h-981zM939 85h-896v640h896v-640z" />
+    <glyph glyph-name="iconlingcunwei" unicode="&#xe67f;" 
+d="M448 320h128v-128h-128v128zM640 320h128v-128h-128v128zM832 320h128v-128h-128v128zM832 832h-768v-896h896v128h-768v640h64v-256h448v256h128v-256h128v256zM640 512h-128v192h128v-192z" />
+    <glyph glyph-name="iconetl" unicode="&#xe680;" 
+d="M480 306h-283q0 -35 10.5 -61.5t29.5 -43.5q18 -16 42.5 -24.5t54.5 -8.5q39 0 78.5 16t56.5 31h3v-71q-32 -13 -66 -23q-34 -9 -72 -9q-95 0 -149 52t-54 147q0 94 51.5 149.5t135.5 55.5q78 0 120 -45.5t42 -129.5v-35zM417 356q0 51 -25.5 78.5t-76.5 27.5
+q-52 0 -83 -30.5t-35 -75.5h220zM763 124q-18 -4 -39 -7q-21 -4 -39 -4q-59 0 -89.5 32t-30.5 101v205h-43v54h43v110h65v-110h133v-54h-133v-175q0 -31 1.5 -48t9.5 -31q7 -14 20.5 -20.5t40.5 -6.5q16 0 33 5q18 5 25 8h3v-59zM893 121h-65v535h65v-535z" />
+    <glyph glyph-name="iconsql" unicode="&#xe681;" 
+d="M392 298q0 -53 -43.5 -86.5t-118.5 -33.5q-43 0 -78 10q-36 10 -60 22v73h3q31 -23 68.5 -36.5t71.5 -13.5q43 0 67 13.5t24 43.5q0 23 -13 34.5t-50 19.5q-15 3 -36 7q-23 5 -41 9q-50 14 -71 40t-21 63q0 24 9 45q10 21 30 38q19 16 49 25.5t67 9.5q34 0 69 -9
+q35 -8 59 -20v-69h-3q-25 18 -60.5 30.5t-69.5 12.5q-35 0 -59.5 -13.5t-24.5 -40.5q0 -24 14 -36q15 -12 47 -19q18 -5 40 -9q21 -4 37 -7q45 -10 70 -36q24 -25 24 -67zM768 46h-65v185q-30 -26 -59 -39q-30 -12 -64 -12q-69 0 -109.5 52.5t-40.5 145.5q0 50 14 87.5
+t38 63.5q23 26 53.5 39.5t64.5 13.5q30 0 54 -7t49 -20l4 16h61v-525v0zM703 285v217q-27 12 -47 17q-21 5 -45 5q-56 0 -85 -38t-29 -105t23.5 -103.5t73.5 -36.5q28 0 56.5 12.5t52.5 31.5zM932 187h-65v535h65v-535z" />
+    <glyph glyph-name="iconxls" unicode="&#xe682;" 
+d="M452 121h-82l-108 148l-110 -148h-75l149 192l-148 192h81l109 -145l108 145h76l-151 -189zM573 121h-64v535h64v-535zM947 232q0 -53 -43.5 -86.5t-118.5 -33.5q-42 0 -78 10q-35 10 -60 22v73h4q30 -23 67.5 -36.5t72.5 -13.5q42 0 66 13.5t24 43.5q0 22 -13 34t-50 20
+q-14 3 -36 7q-23 5 -40 9q-51 14 -72 40t-21 63q0 24 10 45t30 37q19 17 48.5 26t66.5 9q34 0 70 -8q35 -8 58 -20v-69h-3q-25 18 -60.5 30.5t-69.5 12.5q-35 0 -59.5 -13.5t-24.5 -40.5q0 -24 15 -36q14 -12 47 -20q18 -4 40 -8q20 -4 37 -7q44 -11 69 -36q24 -25 24 -67z
+" />
+    <glyph glyph-name="iconshuaxin" unicode="&#xe683;" 
+d="M829 701q-62 62 -144 96.5t-173 34.5q-122 0 -225 -60t-163 -163t-60 -225h112q0 139 98.5 237.5t237.5 98.5q68 0 129.5 -26t108.5 -72l-126 -126h336v336zM512 48q-68 0 -129.5 26t-108.5 72l126 126h-336v-336l131 131q62 -62 144 -96.5t173 -34.5q122 0 225 60
+t163 163t60 225h-112q0 -139 -98.5 -237.5t-237.5 -98.5z" />
+    <glyph glyph-name="iconguanlianshitu" unicode="&#xe684;" 
+d="M640 832v-251l-256 -256v251h-320v-640h320v299l256 256v-299h320v640h-320zM320 0h-192v512h192v-512zM896 256h-192v512h192v-512z" />
+    <glyph glyph-name="iconpingpushitu" unicode="&#xe685;" 
+d="M128 768h192v-192h-192v192zM448 768h192v-192h-192v192zM768 768h192v-192h-192v192zM128 448h192v-192h-192v192zM448 448h192v-192h-192v192zM768 448h192v-192h-192v192zM128 128h192v-192h-192v192zM448 128h192v-192h-192v192zM768 128h192v-192h-192v192z" />
+    <glyph glyph-name="icon26ceshilianjie" unicode="&#xe686;" 
+d="M384 144h-256q-20 0 -34 14t-14 34v384q0 20 14 34t34 14h256q20 0 34 -14t14 -34t-14 -34t-34 -14h-208v-288h208q20 0 34 -14t14 -34t-14 -34t-34 -14zM896 144h-256q-20 0 -34 14t-14 34t14 34t34 14h208v288h-208q-20 0 -34 14t-14 34t14 34t34 14h256q20 0 34 -14
+t14 -34v-384q0 -20 -14 -34t-34 -14zM704 336h-384q-20 0 -34 14t-14 34t14 34t34 14h384q20 0 34 -14t14 -34t-14 -34t-34 -14z" />
+    <glyph glyph-name="iconchaolianjie" unicode="&#xe688;" 
+d="M616 492q-10 10 -22 18l-69 -69q13 -8 23 -18l3 -4q34 -33 34 -80.5t-34 -81.5l-191 -191q-33 -33 -80.5 -33t-81.5 33l-4 4q-33 33 -33 81t33 81l87 86q-23 56 -22 116l-133 -133q-62 -62 -62 -150t62 -150l3 -3q62 -62 150 -62t150 62l191 191q61 61 61 149t-61 150z
+M898 767l-3 3q-62 62 -150 62t-150 -62l-191 -191q-61 -61 -61 -149t61 -150l4 -4q9 -9 22 -19l69 70q-13 8 -23 18l-3 3q-34 34 -34 81.5t34 81.5l191 191q33 33 80.5 33t81.5 -33l4 -4q33 -34 33 -81.5t-33 -80.5l-87 -87q23 -55 22 -115l133 133q62 62 62 150t-62 150z
+" />
+    <glyph glyph-name="iconguanbi" unicode="&#xe689;" 
+d="M580 384l363 363q14 14 14 34t-14 34t-34 14t-34 -14l-363 -363l-363 363q-14 14 -34 14t-34 -14t-14 -34t14 -34l363 -363l-363 -363q-14 -14 -14 -34t14 -34t34 -14t34 14l363 363l363 -363q14 -14 34 -14t34 14t14 34t-14 34z" />
+    <glyph glyph-name="iconshangchuan" unicode="&#xe68a;" 
+d="M768 640q-2 0 -4.5 -0.5t-4.5 -0.5q-21 84 -89.5 138.5t-157.5 54.5t-157.5 -54.5t-89.5 -138.5q-2 0 -4.5 0.5t-4.5 0.5q-106 0 -181 -75t-75 -181t75 -181t181 -75h128v-128v-64h64h192v64v128h128q106 0 181 75t75 181t-75 181t-181 75zM576 320v-192v-128h-128v128
+v192h-192l256 256l256 -256h-192z" />
+    <glyph glyph-name="icontupianchicun" unicode="&#xe68b;" 
+d="M896 128v512v128h-128h-512v128h-128v-128h-128v-128h128v-512v-128h128h512v-128h128v128h128v128h-128zM768 128h-512v512h512v-512zM320 576h384v-384h-384v384z" />
+    <glyph glyph-name="iconchaolianjiekongjian" unicode="&#xe68c;" 
+d="M43 768v-768h938v768h-938zM490.5 725q26.5 0 45.5 -18.5t19 -45t-19 -45.5t-45.5 -19t-45 19t-18.5 45.5t18.5 45t45 18.5zM320 725q26 0 45 -18.5t19 -45t-19 -45.5t-45 -19t-45 19t-19 45.5t19 45t45 18.5zM149.5 725q26.5 0 45 -18.5t18.5 -45t-18.5 -45.5t-45 -19
+t-45.5 19t-19 45.5t19 45t45.5 18.5zM939 43h-854v512h854v-512zM213 469h598v-85h-598v85zM213 341h598v-85h-598v85zM213 213h598v-85h-598v85z" />
+    <glyph glyph-name="icontupiankongjian" unicode="&#xe68d;" 
+d="M43 768v-768h938v768h-938zM939 43h-854v682h854v-682zM768 555zM683 554.5q0 35.5 25 60.5t60 25t60 -25t25 -60.5t-25 -60.5t-60 -25t-60 25t-25 60.5zM683 341l-128 -128l-256 342l-171 -470h768z" />
+    <glyph glyph-name="iconfuzhidaofenzu" unicode="&#xe68e;" 
+d="M576 320l192 160l-192 160v-128h-384v-64h384v-128zM64 704h64v-640h-64v640zM64 64h768v-64h-768v64zM192 832v-256h64v192h640v-576h-640v192h-64v-256h768v704h-768z" />
+    <glyph glyph-name="icontianjiafenzu" unicode="&#xe68f;" 
+d="M448 768h64v-704h-64v704zM128 448h704v-64h-704v64z" />
+    <glyph glyph-name="iconyichufenzu" unicode="&#xe690;" 
+d="M768 256l192 160l-192 160v-128h-512v-64h512v-128zM704 640v192h-640v-832h640v192h-64v-128h-512v704h512v-128h64z" />
+    <glyph glyph-name="iconyidaofenzu" unicode="&#xe691;" 
+d="M576 256l192 160l-192 160v-128h-512v-64h512v-128zM320 640v192h640v-832h-640v192h64v-128h512v704h-512v-128h-64z" />
+    <glyph glyph-name="iconfenlei" unicode="&#xe694;" 
+d="M320 768h640v-128h-640v128zM320 448h640v-128h-640v128zM320 128h640v-128h-640v128zM64 768h128v-128h-128v128zM64 448h128v-128h-128v128zM64 128h128v-128h-128v128z" />
+    <glyph glyph-name="iconxilie" unicode="&#xe695;" 
+d="M448 64v256h192v128h-192v256h192v128h-192q-26 0 -47 -7t-34 -18.5t-23 -25t-14 -27t-6.5 -25t-3.5 -18.5v-7v-256h-128v-128h128v-256h-128v-128h640v128h-384z" />
+    <glyph glyph-name="bi40qietuzitibeijing" unicode="&#xe69b;" 
+d="M371 128l44 147l33 33v12v64v64h-64v64h-256v-64h192v-64h-128h-64v-64h-64v-128h64v-64h64h128h51zM192 320h128v-128h-128v128zM652 512h-12v192h-128v-332zM768 236v-44h-44l-64 -64h172v64h64v172zM887 465l-303 -302l-136 -35l45 125l303 303z" />
+    <glyph glyph-name="bi40qietuzitiyanse" unicode="&#xe69c;" 
+d="M867 128h-174l-45 128h-241l-46 -128h-169l241 640h193zM607 384l-80 233l-80 -233h160z" />
+    <glyph glyph-name="iconzitibeijingbg" unicode="&#xe69d;" 
+d="M64 448h896v-128h-896v128z" />
+    <glyph glyph-name="iconshuoming25" unicode="&#xe69e;" 
+d="M512 896q-139 0 -257 -68.5t-186.5 -186.5t-68.5 -257t68.5 -257t186.5 -186.5t257 -68.5t257 68.5t186.5 186.5t68.5 257t-68.5 257t-186.5 186.5t-257 68.5zM576 64h-128v128h128v-128zM702 426q-17 -23 -63 -59l-30 -24q-27 -21 -33 -41q-2 -4 -3 -16t-2 -21l-1 -9
+h-116q2 66 14 96q10 24 57 61l31 24q16 12 25 24q17 24 17 52q0 32 -19 59t-69 27q-28 0 -44.5 -5t-26.5 -21q-3 -4 -5.5 -10t-4.5 -11.5t-3.5 -11.5t-3 -11t-2.5 -9t-1 -6v-2h-124q2 51 24.5 96t60.5 70q45 29 124 29q95 0 161 -48q64 -47 64 -138q0 -57 -27 -95z" />
+    <glyph glyph-name="icontubiaobiaojidenghao" unicode="&#xe69f;" 
+d="M128 640h768v-128h-768v128zM128 256h768v-128h-768v128z" />
+    <glyph glyph-name="icontubiaobiaojishangjiantou" unicode="&#xe6a0;" 
+d="M0 134q46 -26 94 -42.5t99 -23t97.5 0t88 32.5t71 69t46 114t14.5 164h-254l384 384l384 -384h-248q2 -98 -17.5 -178.5t-55.5 -136t-86.5 -94t-109.5 -55t-124.5 -15.5t-131 20t-130.5 56t-121 89z" />
+    <glyph glyph-name="icontubiaobiaojixiajiantou" unicode="&#xe6a1;" 
+d="M1024 634q-46 25 -94 42t-99 23.5t-97.5 -0.5t-88 -32.5t-71 -68.5t-46 -114t-14.5 -164h254l-384 -384l-384 384h248q-2 98 17.5 178.5t55.5 136t86.5 94t109.5 55t124.5 15.5t131 -20t130.5 -56t121 -89z" />
+    <glyph glyph-name="icontubiaobiaojiyuan" unicode="&#xe6a2;" 
+d="M512 384zM64 384q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5t-131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5z" />
+    <glyph glyph-name="xiala-copy" unicode="&#xe607;" 
+d="M366 634l322 -219q17 -12 17 -32.5t-17 -31.5l-322 -219q-16 -10 -31.5 0.5t-15.5 31.5v438q0 21 15.5 31.5t31.5 0.5z" />
+    <glyph glyph-name="iconjisuanzhibiao" unicode="&#xe6a3;" 
+d="M960 541v4v5t-0.5 4.5t-1.5 3.5t-2 1h-90q-8 0 -18 -12l-93 -107q-7 -9 -12 1l-51 105q-7 13 -16 13h-146q-4 0 -11 -6.5t-7 -11.5v7q0 4 -3.5 7.5t-7.5 3.5h-92l23 94q3 12 17 27.5t28 25.5q23 16 54 21.5t49.5 4t55.5 -8.5t44 -8v91q-1 0 -23.5 5t-30 6.5t-32 5
+t-38 2.5t-37.5 -3t-42 -8.5t-40 -17.5t-42 -27q-52 -42 -68 -114l-25 -96h-171q-4 0 -7.5 -3.5t-3.5 -7.5v-90q0 -4 3.5 -7.5t7.5 -3.5h142l-88 -343q-5 -18 -12.5 -30t-15 -15.5t-14.5 -4.5t-12 0l-4 1h-63v-112h63q27 0 44 1.5t37.5 7.5t32.5 18q32 30 54 131l86 346h120
+q4 0 7.5 3.5t3.5 7.5v-7q0 -4 18 -4h90q9 0 16 -13l36 -74q5 -10 -3 -19l-101 -113q-4 -5 -18 -5h-76q-4 0 -11 -6.5t-7 -11.5v-90q0 -4 18 -4h90q14 0 18 5l128 144q7 9 12 -2l72 -140q3 -7 16 -7h90h3q1 0 1 1v3v90v4v5t-0.5 4.5t-1.5 3.5t-2 1h-34q-13 0 -16 7l-56 110
+q-5 11 2 20l66 75q10 12 18 12h76h3q1 0 1 1v3v90z" />
+    <glyph glyph-name="iconjuzhong" unicode="&#xe6a4;" 
+d="M384 704h320v-64h-320v64zM192 512h704v-64h-704v64zM384 320h320v-64h-320v64zM192 128h704v-64h-704v64z" />
+    <glyph glyph-name="iconjuzuo" unicode="&#xe6a5;" 
+d="M192 704h320v-64h-320v64zM192 512h704v-64h-704v64zM192 320h320v-64h-320v64zM192 128h704v-64h-704v64z" />
+    <glyph glyph-name="iconbudengyu" unicode="&#xe6a6;" 
+d="M256 469h512v-42h-512v42zM256 341h512v-42h-512v42zM345 581l364 -364l-30 -30l-364 364z" />
+    <glyph glyph-name="icondayu" unicode="&#xe6a7;" 
+d="M299 135v-50l426 258v43l-426 254v-53l389 -223z" />
+    <glyph glyph-name="icondayudaijiantou" unicode="&#xe6a8;" 
+d="M640 171l171 -171l170 171h-341zM43 263v-50l426 258v43l-426 254v-53l389 -223z" />
+    <glyph glyph-name="icondayudengyu" unicode="&#xe6a9;" 
+d="M671 456l-372 135v49l426 -158v-52l-426 -158v53zM725 331v-49l-426 -154v43z" />
+    <glyph glyph-name="icondayudengyudaijiantou" unicode="&#xe6aa;" 
+d="M415 542l-372 134v49l426 -157v-53l-426 -157v52zM469 417v-49l-426 -155v43zM640 171l171 -171l170 171h-341z" />
+    <glyph glyph-name="iconxiala" unicode="&#xe6ab;" 
+d="M960 896h-896q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h896q26 0 45 19t19 45v896q0 26 -19 45t-45 19zM896 0h-768v768h768v-768zM704 512h-384l192 -256z" />
+    <glyph glyph-name="icondanchumingxibiao" unicode="&#xe6ac;" 
+d="M960 896h-896q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h896q26 0 45 19t19 45v896q0 26 -19 45t-45 19zM960 -64h-896v896h896v-896zM256 384zM192 384q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM512 384zM448 384q0 26 19 45t45 19
+t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM768 384zM704 384q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45z" />
+    <glyph glyph-name="xiala-copy1" unicode="&#xe6ad;" 
+d="M262 238l219 322q12 17 32.5 17t31.5 -17l219 -322q10 -16 -0.5 -31.5t-31.5 -15.5h-438q-21 0 -31.5 15.5t-0.5 31.5z" />
+    <glyph glyph-name="xiala-copy-copy" unicode="&#xe6ae;" 
+d="M658 134l-322 219q-17 12 -17 32.5t17 31.5l322 219q16 10 31.5 -0.5t15.5 -31.5v-438q0 -21 -15.5 -31.5t-31.5 -0.5z" />
+    <glyph glyph-name="iconshishibaobiaoxiaotu" unicode="&#xe6af;" 
+d="M640 832h-512q-18 0 -31 -7t-19 -16.5t-9.5 -19t-4.5 -16.5v-7v-766q0 -28 16 -44t32 -18l16 -2h704q28 0 44 16t18 32l2 16v576zM659 576q51 -41 80 -99t29 -125q0 -119 -84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5q87 0 160 -49v177
+l192 -192h-173zM448 384h-128v-64h128h64v256h-64v-192z" />
+    <glyph glyph-name="icondanxuanweixuanze" unicode="&#xe6b0;" 
+d="M512 704q132 0 226 -94t94 -226t-94 -226t-226 -94t-226 94t-94 226t94 226t226 94zM512 768q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5v0z" />
+    <glyph glyph-name="icondanxuanxuanze" unicode="&#xe6b1;" 
+d="M512 768q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5zM512 256q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5z" />
+    <glyph glyph-name="iconduoxuanweixuanze" unicode="&#xe6b2;" 
+d="M832 704v-640h-640v640h640zM832 768h-640q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v640q0 26 -19 45t-45 19v0z" />
+    <glyph glyph-name="iconduoxuanxuanze" unicode="&#xe6b3;" 
+d="M832 768h-640q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v640q0 26 -19 45t-45 19zM774 521l-342 -342q-14 -14 -34 -14h-5q-22 2 -35 21l-114 171q-11 17 -7 36.5t20.5 30.5t36 7t30.5 -20l81 -123l301 301q14 14 34 14t34 -14t14 -34
+t-14 -34z" />
+    <glyph glyph-name="iconhuifu" unicode="&#xe6b4;" 
+d="M545 795q-85 0 -159 -28.5t-129 -80.5t-87.5 -130t-32.5 -172h-93l142 -196l142 196h-93q0 141 89 227t221 86q128 0 218.5 -90t90.5 -217.5t-90.5 -218t-218.5 -90.5q-21 0 -35 -14t-14 -34.5t14 -34.5t35 -14q110 0 204 54t148.5 147.5t54.5 204t-54.5 204
+t-148.5 147.5t-204 54z" />
+    <glyph glyph-name="iconquxiaofenxiang" unicode="&#xe6b5;" 
+d="M908 372q-14 14 -34 14t-34 -14l-120 -120l-121 120q-14 14 -33.5 14t-34 -14t-14.5 -34t14 -34l121 -120l-121 -121q-14 -14 -14 -33.5t14.5 -33.5t34 -14t33.5 14l121 120l120 -120q14 -14 34 -14t34 14t14 33.5t-14 33.5l-121 121l121 120q14 14 14 34t-14 34z
+M401 258q48 55 48 126q0 28 -11 59l169 92q27 -40 69 -63.5t92 -23.5q80 0 136 56t56 136t-56 136t-136 56t-136 -56t-56 -136q0 -21 6 -46l-173 -94q-27 35 -67 55.5t-85 20.5q-80 0 -136 -56t-56 -136t56 -136t136 -56q48 0 94 25l75 -75q9 -9 22.5 -9t23 9t9.5 22.5
+t-10 22.5zM768 736q40 0 68 -28t28 -68t-28 -68t-68 -28t-68 28t-28 68t28 68t68 28zM161 384q0 40 28 68t67.5 28t68 -28t28.5 -68t-28.5 -68t-68 -28t-67.5 28t-28 68z" />
+    <glyph glyph-name="iconshangchuan1" unicode="&#xe6ba;" 
+d="M384 192h256v320h168q22 0 29.5 21t-9.5 36l-296 246q-8 7 -20 7t-20 -7l-296 -246q-17 -15 -9.5 -36t29.5 -21h168v-320zM704 256v-128h-384v128h-256v-320h896v320h-256zM768 0h-64v64h64v-64zM896 0h-64v64h64v-64z" />
+    <glyph glyph-name="iconshangjiantou" unicode="&#xe6bb;" 
+d="M556 115l259 302q24 28 8.5 61.5t-52.5 33.5h-518q-37 0 -52.5 -33.5t8.5 -61.5l259 -302q18 -20 44 -20t44 20z" />
+    <glyph glyph-name="iconxiajiantou" unicode="&#xe6bc;" 
+d="M556 589l259 -302q24 -28 8.5 -61.5t-52.5 -33.5h-518q-37 0 -52.5 33.5t8.5 61.5l259 302q18 20 44 20t44 -20z" />
+    <glyph glyph-name="iconyoujiantou" unicode="&#xe6bd;" 
+d="M717 431l-302 259q-28 24 -61.5 8.5t-33.5 -52.5v-517q0 -37 33.5 -52.5t61.5 8.5l302 259q20 17 20 43.5t-20 43.5z" />
+    <glyph glyph-name="iconzuojiantou" unicode="&#xe6be;" 
+d="M307 431l302 259q28 24 61.5 8.5t33.5 -52.5v-517q0 -37 -33.5 -52.5t-61.5 8.5l-302 259q-20 17 -20 43.5t20 43.5z" />
+    <glyph glyph-name="iconzitibeijing1" unicode="&#xe696;" 
+d="M663 534l-151 151v104h-256v-276l-193 -194l362 -362l332 333q28 -111 19 -214q-1 -15 11.5 -22t23.5 3q25 22 48 48t47.5 63t39 82.5t14.5 92.5q0 38 -16.5 69t-45 51t-59.5 34t-67.5 21.5t-61 10.5t-47.5 5zM320 725h128v-20l-128 -128v148zM425 48l-272 271l295 295
+v-209h64v189l216 -216q2 -4 8 -19z" />
+    <glyph glyph-name="gougou-copy" unicode="&#xe6dd;" 
+d="M720 565q-13 10 -29 7.5t-25 -15.5l-211 -286l-98 122q-10 12 -25.5 14t-28 -8t-14.5 -26t8 -28l130 -161q12 -14 30 -14h1q19 0 30 15l240 326q9 13 6.5 29t-14.5 25v0zM720 565zM512 834q-186 0 -318 -132t-132 -318t132 -318t318 -132t318 132t132 318t-132 318
+t-318 132v0zM512 22q-98 0 -181.5 48.5t-132 132t-48.5 181.5t48.5 181.5t132 132t181.5 48.5t181.5 -48.5t132 -132t48.5 -181.5t-48.5 -181.5t-132 -132t-181.5 -48.5v0zM512 22z" />
+    <glyph glyph-name="iconbiaogefanyejiantoushang" unicode="&#xe698;" 
+d="M876.5 128q-30.5 0 -51.5 22l-313 312l-313 -312q-21 -22 -51.5 -22t-52 21.5t-21.5 52t21 52.5l365 364q22 22 52.5 22t51.5 -22l365 -364q21 -22 21 -52.5t-21.5 -52t-52 -21.5z" />
+    <glyph glyph-name="iconbiaogefanyejiantouxia" unicode="&#xe699;" 
+d="M147.5 640q30.5 0 51.5 -22l313 -312l313 312q21 22 51.5 22t52 -21.5t21.5 -52t-21 -52.5l-365 -364q-22 -22 -52.5 -22t-51.5 22l-365 364q-21 22 -21 52.5t21.5 52t52 21.5z" />
+    <glyph glyph-name="iconbiaogefanyejiantouyou" unicode="&#xe6b6;" 
+d="M256 19.5q0 30.5 22 51.5l312 313l-312 313q-22 21 -22 51.5t21.5 52t52 21.5t52.5 -21l364 -365q22 -22 22 -52.5t-22 -51.5l-364 -365q-22 -21 -52.5 -21t-52 21.5t-21.5 52z" />
+    <glyph glyph-name="iconbiaogefanyejiantouzuo" unicode="&#xe6b7;" 
+d="M768 748.5q0 -30.5 -22 -51.5l-312 -313l312 -313q22 -21 22 -51.5t-21.5 -52t-52 -21.5t-52.5 21l-364 365q-22 22 -22 52.5t22 51.5l364 365q22 21 52.5 21t52 -21.5t21.5 -52z" />
+    <glyph glyph-name="iconbiaogegundongtiaojiantoushang" unicode="&#xe6b8;" 
+d="M0 128h1024l-512 512z" />
+    <glyph glyph-name="iconbiaogegundongtiaojiantouxia" unicode="&#xe6b9;" 
+d="M1024 640h-1024l512 -512z" />
+    <glyph glyph-name="iconbiaogegundongtiaojiantouyou" unicode="&#xe6bf;" 
+d="M256 896v-1024l512 512z" />
+    <glyph glyph-name="iconbiaogegundongtiaojiantouzuo" unicode="&#xe6c0;" 
+d="M768 896v-1024l-512 512z" />
+    <glyph glyph-name="iconliandongfenzu" unicode="&#xe6c1;" horiz-adv-x="1639" 
+d="M1098 458h-296l109 -112l-197 -203l68 -69l202 202l114 -112v294zM1244 664h-640q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h640q27 0 45.5 19t18.5 45v640q0 26 -18.5 45t-45.5 19zM1212 -8h-576v576h576v-576zM1026 776v96h-632q-26 0 -45 -19t-19 -45v-670h96
+v638h600z" />
+    <glyph glyph-name="qidonghuamianbangzhu" unicode="&#xe6c7;" 
+d="M512 766q77 0 146.5 -29t123.5 -83t83 -124t29 -146.5t-29 -146t-83 -123.5t-124 -83t-146.5 -29t-146 29t-123.5 83t-83 124t-29 146.5t29 146t83 123.5t124 83t146 29v0zM512 811q-85 0 -163 -32.5t-138.5 -93t-93 -138.5t-32.5 -163t32.5 -163t93 -138.5t138.5 -93
+t163 -32.5t163 32.5t138.5 93t93 138.5t32.5 163t-32.5 163t-93 138.5t-138.5 93t-163 32.5v0zM512 208zM629.5 593q-42.5 38 -110.5 38q-77 0 -122 -45.5t-45 -124.5v0q1 -12 10 -20.5t21 -8.5t21 8.5t10 20.5v0v2v0v0q1 117 102 117q39 0 64.5 -23t25.5 -58q0 -42 -47 -84
+l-23 -21q-35 -31 -44.5 -54t-9.5 -73v0v-3q0 -12 8.5 -20.5t20.5 -8.5q11 0 19 8t9 19v0l1 11q0 52 49 92q83 68 83 130q0 60 -42.5 98zM512 164zM473 164zM544 132q0 -14 -9.5 -23.5t-22.5 -9.5t-22.5 9.5t-9.5 23t9.5 23t22.5 9.5t22.5 -9.5t9.5 -22.5v0z" />
+    <glyph glyph-name="qidonghuamiangengxin" unicode="&#xe6c8;" 
+d="M138 440q7 0 13 4l116 76q8 6 10 15.5t-3 17.5t-15 10t-18 -3l-65 -43q40 98 128.5 158t195.5 60q117 0 211.5 -71.5t126.5 -183.5q5 -17 23 -17h6q9 3 14 11.5t2 18.5q-36 128 -143 208.5t-240 80.5q-124 0 -227 -71.5t-146 -187.5l-46 70q-6 8 -15.5 10t-17.5 -3.5
+t-10 -15t3 -17.5l77 -116q7 -11 20 -11v0zM982 267l-82 112q-9 12 -24 9q-5 -1 -9 -4l-113 -82q-8 -6 -9.5 -15.5t4.5 -17.5q7 -10 19 -10q8 0 14 5l61 44q-27 -119 -123 -197t-220 -78q-131 0 -230 86.5t-117 216.5q-2 9 -9.5 15t-17.5 5t-16 -9t-4 -18q20 -147 133 -245
+t261 -98q143 0 254 92t138 232l52 -71q7 -10 19 -10q8 0 14 4q8 6 9.5 16t-4.5 18v0z" />
+    <glyph glyph-name="qidonghuamianzaicijinru" unicode="&#xe6c9;" 
+d="M804 -14h-531q-44 0 -75 31t-31 75v44h53v-44q0 -22 15.5 -37.5t37.5 -15.5h531q22 0 37.5 15.5t15.5 37.5v584q0 22 -15.5 37.5t-37.5 15.5h-531q-22 0 -37.5 -15.5t-15.5 -37.5v-49h-53v49q0 44 31 75t75 31h531q44 0 75 -31t31 -75v-584q0 -44 -31 -75t-75 -31v0z
+M531 550q-8 7 -8 18t8 19t19 8t19 -8l183 -183q8 -8 7 -20q1 -12 -7 -20l-183 -183q-8 -8 -19 -8t-19 7.5t-8 18.5t8 19l139 139h-530q-11 0 -18.5 8t-7.5 19t7.5 19t18.5 8h530l-139 139v0zM193 160v0q11 0 19 -8t8 -19v-17q0 -11 -8 -18.5t-19 -7.5v0q-11 0 -18.5 7.5
+t-7.5 18.5v17q0 11 7.5 19t18.5 8zM193 705v0q11 0 19 -8t8 -19v-52q0 -11 -8 -19t-19 -8v0q-11 0 -18.5 8t-7.5 19v52q0 11 7.5 19t18.5 8z" />
+    <glyph glyph-name="quanjuyangshi" unicode="&#xe6ca;" horiz-adv-x="1639" 
+d="M706 738v-244h-245v244h245zM731 828h-296q-26 0 -45 -19t-19 -45v-296q0 -26 19 -45t45 -19h296q27 0 45.5 19t18.5 45v296q0 26 -18.5 45t-45.5 19v0zM1178 738v-244h-245v244h245zM1203 828h-296q-26 0 -45 -19t-19 -45v-296q0 -26 19 -45t45 -19h296q27 0 45.5 19
+t18.5 45v296q0 26 -18.5 45t-45.5 19v0zM706 270v-244h-245v244h245zM731 360h-296q-26 0 -45 -19t-19 -45v-296q0 -26 19 -45t45 -19h296q27 0 45.5 19t18.5 45v296q0 26 -18.5 45t-45.5 19v0zM1178 270v-244h-245v244h245zM1203 360h-296q-26 0 -45 -19t-19 -45v-296
+q0 -26 19 -45t45 -19h296q27 0 45.5 19t18.5 45v296q0 26 -18.5 45t-45.5 19v0z" />
+    <glyph glyph-name="shangchuantupian" unicode="&#xe6cb;" 
+d="M247 618zM143 618q0 43 30.5 73.5t73.5 30.5t73.5 -30.5t30.5 -73.5t-30.5 -73.5t-73.5 -30.5t-73.5 30.5t-30.5 73.5zM548 -77h-548v959h959v-582h-68v514h-822v-823h479v-68zM851 26h171l-231 314l-231 -314h154v-137h137v137zM730 396l-56 169l-236 -333l-118 119
+l-196 -257h390z" />
+    <glyph glyph-name="jiantouzuo" unicode="&#xe6cc;" 
+d="M778 896l-542 -511l542 -513l33 36l-505 477l505 476z" />
+    <glyph glyph-name="jiantouyou" unicode="&#xe6cd;" 
+d="M269 -128l542 511l-542 513l-33 -35l504 -478l-504 -475z" />
+    <glyph glyph-name="biaoqianxianshiweizhineice" unicode="&#xe6ce;" 
+d="M0 896v-1024h1024v1024h-1024zM981 -85h-938v938h938v-938v0zM169 734h683v-426h-683v426z" />
+    <glyph glyph-name="biaoqianxianshiweizhiwaice" unicode="&#xe6cf;" horiz-adv-x="1025" 
+d="M0 384v-512h1024v512h-1024zM981 -85h-938v426h938v-426v0zM168 896h682v-427h-682v427z" />
+    <glyph glyph-name="biaoqianxianshiweizhijuzhong" unicode="&#xe6d0;" 
+d="M2 715v-843h1020v843h-172v181h-680l-1 -181h-167zM979 -85h-934v758h125v-176h680v176h129v-758z" />
+    <glyph glyph-name="kongjiandanzhihuakuai" unicode="&#xe6d1;" horiz-adv-x="1026" 
+d="M1 676h46v-92h-46v92zM47 722h46v-92h-46v92zM93 767h92v-412h-92v412zM322 722h92v-46h-92v46zM368 767h229v-45h-229v45zM551 722h92v-138h-92v138zM506 630h91v-92h-91v92zM460 584h46v-92h-46v92zM506 538h45v-46h-45v46zM414 538h92v-92h-92v92zM368 492h92v-91h-92
+v91zM322 446h46v-91h-46v91zM368 401h275v-46h-275v46zM689 722h92v-46h-92v46zM735 767h229v-45h-229v45zM918 722h92v-92h-92v92zM827 630h137v-46h-137v46zM918 584h92v-138h-92v138zM918 446h46v-45h-46v45zM689 446h92v-45h-92v45zM735 401h183v-46h-183v46zM17 136
+h1008v-92h-1008v92zM460 205h138v-229h-138v229z" />
+    <glyph glyph-name="kongjianliebiaoshu" unicode="&#xe6d2;" 
+d="M0 881h420v-250h-420v250zM1024 385v127h-604v-45h-241v164h-37v-700h37v0h241v-44h604v126h-604v-44h-241v214h241v-45h604v127h-604v-45h-241v210h241v-45h604z" />
+    <glyph glyph-name="kongjianqujianhuakuai" unicode="&#xe6d3;" 
+d="M0 660h46v-93h-46v93zM46 706h47v-93h-47v93zM93 753h93v-419h-93v419zM325 706h93v-46h-93v46zM372 753h232v-47h-232v47zM558 706h93v-139h-93v139zM511 613h93v-93h-93v93zM465 567h46v-93h-46v93zM511 520h47v-46h-47v46zM418 520h93v-93h-93v93zM372 474h93v-93h-93
+v93zM325 427h47v-93h-47v93zM372 381h279v-47h-279v47zM697 706h93v-46h-93v46zM744 753h232v-47h-232v47zM929 706h93v-93h-93v93zM837 613h139v-46h-139v46zM929 567h93v-140h-93v140zM929 427h47v-46h-47v46zM697 427h93v-46h-93v46zM744 381h185v-47h-185v47zM630 205
+v-70h-418v70h-139v-232h139v69h418v-69h140v232h-140z" />
+    <glyph glyph-name="kongjianshubiaoqian" unicode="&#xe6d4;" 
+d="M0 884h423v-251h-423v251zM591 386v127h-168v-45h-243v165h-37v-704h37v0h243v-45h168v127h-168v-44h-243v215h243v-45h168v127h-168v-44h-243v211h243v-45h168zM639 513h169v-127h-169v127zM639 264h169v-126h-169v126zM856 513h168v-127h-168v127zM856 264h168v-126
+h-168v126zM639 10h169v-126h-169v126zM856 10h168v-126h-168v126z" />
+    <glyph glyph-name="kongjianshuzhiqujian" unicode="&#xe6d5;" horiz-adv-x="1025" 
+d="M0 674h47v-93h-47v93zM47 721h46v-93h-46v93zM93 767h93v-418h-93v418zM326 721h93v-47h-93v47zM372 767h233v-46h-233v46zM559 721h93v-140h-93v140zM512 628h93v-93h-93v93zM465 581h47v-93h-47v93zM512 535h47v-47h-47v47zM419 535h93v-93h-93v93zM372 488h93v-93h-93
+v93zM326 442h46v-94h-46v94zM372 395h280v-46h-280v46zM698 721h93v-47h-93v47zM745 767h232v-46h-232v46zM931 721h93v-93h-93v93zM838 628h139v-47h-139v47zM931 581h93v-139h-93v139zM931 442h46v-47h-46v47zM698 442h93v-47h-93v47zM745 395h186v-46h-186v46zM90 223
+h140v-233h-140v233zM835 223h140v-233h-140v233zM370 130h46v-47h-46v47zM416 177h93v-47h-93v47zM509 130h47v-47h-47v47zM556 83h93v-46h-93v46zM649 130h47v-47h-47v47z" />
+    <glyph glyph-name="kongjianwenbenbiaoqian" unicode="&#xe6d6;" horiz-adv-x="1026" 
+d="M117 558h492v-85h-492v85zM117 294h114v-85h-114v85zM338 294h113v-85h-113v85zM562 294h114v-85h-114v85zM784 294h114v-85h-114v85zM1026 -64h-1024v896h1024v-896zM44 -21h939v810h-939v-810z" />
+    <glyph glyph-name="kongjianwenbenliebiao" unicode="&#xe6d7;" 
+d="M290 504h615v-85h-615v85zM120 683h483v-86h-483v86zM290 333h615v-85h-615v85zM290 163h615v-86h-615v86zM120 504h85v-85h-85v85zM120 333h85v-85h-85v85zM120 163h85v-86h-85v86zM1024 -64h-1024v896h1024v-896zM43 -21h938v810h-938v-810z" />
+    <glyph glyph-name="kongjianwenbenxiala" unicode="&#xe6d8;" horiz-adv-x="1026" 
+d="M1026 -69h-1024v896h614v-43h-572v-811h939v686h43v-728zM292 505h614v-85h-614v85zM122 684h482v-85h-482v85zM292 335h614v-86h-614v86zM292 164h614v-85h-614v85zM122 505h85v-85h-85v85zM122 335h85v-86h-85v86zM122 164h85v-85h-85v85zM989 828l-164 -247l-165 247
+h329z" />
+    <glyph glyph-name="kongjianxialashu" unicode="&#xe6d9;" 
+d="M0 881h420v-250h-420v250zM1024 385v127h-604v-45h-241v164h-37v-700h37v0h241v-44h604v126h-604v-44h-241v214h241v-45h604v127h-604v-45h-241v210h241v-45h604zM1024 877l-161 -241l-160 241h321z" />
+    <glyph glyph-name="quanjudaochu" unicode="&#xe6da;" 
+d="M634 896v-186h160zM211 288h263v-70h-263v70zM211 122h263v-71h-263v71zM211 454h263v-70h-263v70zM1024 243l-198 205v-109h-282v-179h282v-109zM659 -26h-525v602h525v-109h135v186h-212v243h-582v-1024h659h135v0v154h-135v-52z" />
+    <glyph glyph-name="iconshangxiazuan" unicode="&#xe6c2;" 
+d="M189 639v-704h415v704h-415zM521 18h-249v538h249v-538zM50 833v-806h144v77h-74v659h268v-125h72v195h-410zM846 608h128l-160 192l-160 -192h128v-448h-128l160 -192l160 192h-128v448z" />
+    <glyph glyph-name="iconxiazuanyixuanze" unicode="&#xe6c3;" 
+d="M285 555h251v-537h-251v537zM410 640v128h-282v-664h76v536h206zM0 896v-1024h1024v1024h-1024zM618 -64h-414v91h-140v805h410v-192h144v-704zM818 -32l-160 192h128v640h64v-640h128z" />
+    <glyph glyph-name="iconshangxiazuanyixuanze" unicode="&#xe6c4;" 
+d="M280 552h249v-527h-249v527zM396 768h-268v-663h69v535h199v128zM0 896v-1024h1024v1024h-1024zM612 -64h-415v91h-139v805h410v-192h144v-704v0zM986 128l-160 -192l-160 192h124v448h-124l160 192l160 -192h-132v-448h132z" />
+    <glyph glyph-name="iconxiazuan" unicode="&#xe6c5;" 
+d="M204 639v-704h414v704h-414zM536 18h-250v538h250v-538zM64 833v-806h144v77h-73v659h267v-125h72v195h-410zM658 160l160 -192l160 192h-128v640h-64v-640h-128z" />
+    <glyph glyph-name="fuwuqishujuji" unicode="&#xe6db;" 
+d="M73 676.5q0 59.5 59 110t160 80t220 29.5t220 -29.5t160 -80t59 -110t-59 -110t-160 -80t-220 -29.5t-220 29.5t-160 80t-59 110zM512 384q-119 0 -220 29.5t-160 80t-59 109.5v-219q0 -60 59 -110.5t160 -79.5t220 -29t220 29t160 79.5t59 110.5v219q0 -59 -59 -109.5
+t-160 -80t-220 -29.5zM512 91q-119 0 -220 29.5t-160 80t-59 110.5v-220q0 -59 59 -109.5t160 -80t220 -29.5t220 29.5t160 80t59 109.5v220q0 -60 -59 -110.5t-160 -80t-220 -29.5z" />
+    <glyph glyph-name="iconfuzhilianjie" unicode="&#xe6de;" 
+d="M702 -25v-96h-631q-26 0 -45 19t-19 45v670h96v-638h599zM770 642q-8 8 -17 15l-9 6l-69 -69l14 -8q7 -5 14 -11l2 -2q20 -21 20 -49.5t-20 -48.5l-136 -136q-20 -20 -49 -20t-49 20l-3 2q-20 20 -20 49t20 49l68 67l-3 8q-15 37 -14 78v32l-118 -118q-48 -48 -48 -116
+t48 -116l3 -3q48 -48 116 -48t116 48l136 137q48 48 48 116t-48 116zM971 839l-2 2q-48 48 -116.5 48t-115.5 -48l-137 -136q-48 -48 -48 -116t48 -116l3 -3q7 -7 17 -14l8 -7l70 70l-14 8q-8 4 -14 11l-2 2q-21 20 -21 48.5t20 49.5l137 136q19 20 48.5 20t49.5 -20l2 -2
+q20 -21 20 -49.5t-20 -48.5l-68 -68l4 -8q15 -37 14 -77l-1 -32l118 118q48 48 48 116t-48 116zM853 138h-576v576h192v96h-224q-27 0 -45.5 -18.5t-18.5 -45.5v-640q0 -26 18.5 -45t45.5 -19h640q26 0 45 19t19 45v301h-96v-269z" />
+    <glyph glyph-name="more-43" unicode="&#xe6e0;" 
+d="M512 -128q48 0 82 34t34 82.5t-34 82.5t-82 34t-82 -34t-34 -82.5t34 -82.5t82 -34zM512 268q48 0 82 34t34 82t-34 82t-82 34t-82 -34t-34 -82t34 -82t82 -34zM512 663v0q48 0 82 34t34 82.5t-34 82.5t-82 34v0v0q-48 0 -82 -34t-34 -82.5t34 -82.5t82 -34v0z" />
+    <glyph glyph-name="icon_zuidahua" unicode="&#xe6c6;" 
+d="M109 473q-19 0 -32 13t-13 32v263q0 24 13.5 37.5t37.5 13.5h262q18 -1 31 -14t13 -31t-13 -31.5t-31 -14.5h-161l193 -193q13 -13 13 -31t-13 -31t-31 -13t-31 13l-193 193v-161q0 -19 -13 -32t-32 -13zM870 518v161l-193 -193q-13 -13 -31 -13t-31 13t-13 31t13 31
+l193 193h-161q-19 0 -32 13.5t-13 32t13 32t32 13.5h262q24 0 37.5 -13.5t13.5 -37.5v-263v-3q0 -19 -13 -32t-32 -13t-32 13t-13 32v3zM154 246v-161l193 193q13 13 31 13t31 -13t13 -31t-13 -31l-193 -193h161q19 0 32 -13.5t13 -32t-13 -32t-32 -13.5h-262
+q-24 0 -37.5 13.5t-13.5 37.5v263v2q0 18 13 31.5t32 13.5t32 -13.5t13 -31.5v-2zM915 291q19 0 32 -13t13 -32v-263q0 -24 -13.5 -37.5t-37.5 -13.5h-262q-19 0 -32 13.5t-13 32t13 32t32 13.5h161l-193 193q-13 13 -13 31t13 31t31 13t31 -13l193 -193v161v0q0 19 13 32
+t32 13v0z" />
+    <glyph glyph-name="icon_zuixiaohua" unicode="&#xe6df;" 
+d="M377 834q19 0 32 -13.5t13 -31.5v-263q0 -24 -13.5 -37.5t-37.5 -13.5h-262q-19 0 -32 13t-13 32t13 32t32 13h161l-193 194q-13 13 -13 31t13 31q13 12 31 12t31 -12l193 -194v162q0 18 13 31.5t32 13.5zM692 789v-162l193 194q13 12 31 12t31 -12q13 -13 13 -31
+t-13 -31l-193 -194h161q18 0 30.5 -13.5t12.5 -31.5t-12.5 -31.5t-30.5 -13.5h-262q-24 0 -37.5 13.5t-13.5 37.5v263q0 18 13 31.5t32 13.5t32 -13.5t13 -31.5zM332 -21v162l-193 -194q-13 -12 -31 -12t-31 12q-13 13 -13 31t13 31l193 194h-161q-18 0 -30.5 13.5
+t-12.5 31.5t12.5 31.5t30.5 13.5h262q24 0 37.5 -13.5t13.5 -37.5v-263q0 -18 -13 -31.5t-32 -13.5t-32 13.5t-13 31.5zM647 -66q-19 0 -32 13.5t-13 31.5v263q0 24 13.5 37.5t37.5 13.5h262q18 0 31.5 -13t13.5 -32t-13.5 -32t-31.5 -13h-161l193 -194q13 -13 13 -31
+t-13 -31q-13 -12 -31 -12t-31 12l-193 194v-162v0q0 -18 -13 -31.5t-32 -13.5z" />
+    <glyph glyph-name="iconzhongmingming-06" unicode="&#xe6e1;" 
+d="M128 448h384v-128h-384v128zM816 542h142v-316h-142v316zM66 542h558v-316h-558v316zM66 226v316h558v66h-624v-448h624v66h-558zM1024 608h-208v-66h142v-316h-142v-66h208v448zM848 704v64h-256v-64h96v-640h-96v-64h256v64h-96v640h96z" />
+    <glyph glyph-name="-" unicode="&#xe6e2;" 
+d="M995 454q-12 12 -32.5 20.5t-37.5 8.5v0q-24 0 -50 -15l-87 86q9 18 9 37q0 33 -23 56t-55 23h-1q-32 0 -55.5 -23.5t-23.5 -56.5q0 -13 7 -29.5t16 -26.5q24 -23 56 -23q17 0 36 10l87 -87q-14 -23 -14 -50q0 -26 13 -48l-88 -87q-16 8 -34 8q-16 0 -33 -8l-88 87
+q16 28 12.5 61.5t-27.5 56.5q-12 12 -32.5 20.5t-37.5 8.5t-37.5 -8.5t-32.5 -20.5q-23 -23 -27.5 -55t10.5 -60l-89 -89q-14 7 -30 7t-31 -7l-89 89q11 21 11 45t-11 45l89 89q21 -10 45 -5.5t41.5 22t22 41.5t-5.5 45l89 89q28 -15 60 -10.5t55 27.5q11 12 19 31.5t8 36.5
+q0 41 -29 70t-70 29q-16 0 -36 -8t-32 -19q-23 -23 -27.5 -55t10.5 -60l-89 -89q-14 7 -31 7q-13 0 -29.5 -7t-26 -16.5t-16.5 -26t-7 -29.5q0 -17 7 -31l-89 -89q-28 15 -60 10.5t-55 -27.5q-12 -12 -20.5 -32.5t-8.5 -37.5t8.5 -37.5t20.5 -32.5q23 -23 55 -27.5t60 10.5
+l89 -89q-10 -21 -5.5 -45t22 -41.5t41.5 -22t45 5.5l89 -89q-15 -28 -10.5 -60t27.5 -55q12 -11 32 -19t36 -8q41 0 70 29t29 70q0 17 -8 36.5t-19 31.5q-23 23 -55 27.5t-60 -10.5l-89 89q7 15 7 31t-7 30l89 89q46 -24 93 2l87 -88q-7 -16 -7 -34q0 -33 23 -56t55 -23v0v0
+q33 0 56 23t23 56q0 18 -8 34l88 88q25 -14 48 -14v0q41 0 70 29t29 70q0 17 -8.5 37.5t-20.5 32.5zM699.5 571.5q-7.5 7.5 -7.5 18.5t7.5 19t18.5 8t19 -8t8 -19t-8 -18.5t-19 -7.5t-18.5 7.5zM737 159q-8 -8 -19 -8t-18.5 8t-7.5 19t7.5 18.5t18.5 7.5t19 -7.5t8 -18.5
+t-8 -19zM957.5 351.5q-13.5 -13.5 -32.5 -13.5v0v0q-19 0 -32.5 13.5t-13.5 32.5t13.5 32.5t32.5 13.5t32.5 -13.5t13.5 -32.5t-13.5 -32.5z" />
+    <glyph glyph-name="icon_danbiaogengxin_quan-" unicode="&#xe6e3;" 
+d="M672 448h-512v-64h320v-128h-192v-64h192v-128h-320v-64h704v64h-320v128h192v64h-192v128h320v64h-192zM32 832v-896q0 -26 19 -45t45 -19h832q26 0 45 19t19 45v896q0 26 -19 45t-45 19h-832q-26 0 -45 -19t-19 -45zM928 -64h-832v896h832v-896zM480 768
+q-3 -9 -9 -23.5t-28.5 -56.5t-49 -80t-72 -83.5t-97.5 -76.5h128q7 6 18 16.5t40.5 45t54 69.5t48 87t31.5 102h-64zM544 768q3 -9 9 -23.5t28.5 -56.5t49 -80t72 -83.5t97.5 -76.5h-128q-7 5 -18 15t-40.5 42.5t-54 67t-48 88t-31.5 107.5h64z" />
+    <glyph glyph-name="icon_danbiaogengxin_zeng-" unicode="&#xe6e4;" 
+d="M352 192v256h64v-64h64v-384h64v64h192v-64h64v320h-64v-64h-192v64h256v64h64v256h-448v-128h-64v256h-64v-256h-128v-64h128v-256h64zM736 192v-64h-192v64h192zM800 576v-128h-64v64h-64v64h128zM480 576h128v-64h-64v-64h-64v128zM32 832v-896q0 -26 19 -45t45 -19
+h832q26 0 45 19t19 45v896q0 26 -19 45t-45 19h-832q-26 0 -45 -19t-19 -45zM928 -64h-832v896h832v-896zM608 640h-64l-64 128h64zM672 640h64l64 128h-64zM416 192l-256 -128v64l256 128v-64z" />
+    <glyph glyph-name="gengxinchenggong-" unicode="&#xe6e5;" 
+d="M512 808q115 0 213 -56.5t154.5 -154.5t56.5 -213t-56.5 -213t-154.5 -154.5t-213 -56.5t-213 56.5t-154.5 154.5t-56.5 213t56.5 213t154.5 154.5t213 56.5zM512 896q-139 0 -257 -68.5t-186.5 -186.5t-68.5 -257t68.5 -257t186.5 -186.5t257 -68.5t257 68.5
+t186.5 186.5t68.5 257t-68.5 257t-186.5 186.5t-257 68.5zM444 166v0q-18 0 -31 13l-175 175q-12 12 -12 30.5t12.5 31t31 12.5t30.5 -12l144 -144l280 280q12 13 30.5 13t31.5 -13t13 -31t-13 -31l-311 -311q-13 -13 -31 -13v0z" />
+    <glyph glyph-name="gengxinshibai-" unicode="&#xe6e6;" 
+d="M512 896q-104 0 -199 -40.5t-163.5 -109t-109 -163.5t-40.5 -199t40.5 -199t109 -163.5t163.5 -109t199 -40.5t199 40.5t163.5 109t109 163.5t40.5 199t-40.5 199t-109 163.5t-163.5 109t-199 40.5zM512 -28q-112 0 -207 55t-150 150t-55 207t55 207t150 150t207 55
+t207 -55t150 -150t55 -207t-55 -207t-150 -150t-207 -55zM512 -28zM478 715h68q29 0 28 -31l-16 -403q0 -8 -6 -14t-15 -6h-50q-9 0 -15 6t-6 14l-16 403q-1 31 28 31zM512 53q-29 0 -49 20.5t-20 49t20 49t49 20.5t49 -20.5t20 -49t-20 -49t-49 -20.5z" />
+    <glyph glyph-name="icon_xuanxiangqia-" unicode="&#xe6e7;" 
+d="M186 477h652v-93h-652v93zM186 337h652v-93h-652v93zM186 198h652v-93h-652v93zM745 710v-93h-47v93h-279v-93h-47v186h-372v-838h1024v745h-279zM977 12h-930v558h930v-558v0z" />
+    <glyph glyph-name="icon_xuanxiangqiayangshi-" unicode="&#xe6e8;" 
+d="M464 689l-126 -313h59l31 80h138l27 -80h58l-125 313h-62zM441 496l54 139l54 -139h-108zM57 644h107v-268h54v268h112v45h-273v-45zM884 541q27 7 40.5 27t13.5 45q0 37 -27 58q-30 22 -76 22h-152v-313h152q56 0 80 18q36 22 36 72q0 37 -18 49q-16 15 -49 22zM736 648
+h85q32 0 49 -9q14 -6 14 -31q0 -22 -14 -36q-9 -9 -49 -9h-85v85zM875 425q-27 -9 -49 -9h-90v98h90q33 0 53 -13q18 -18 18 -40q0 -21 -22 -36zM1024 131.5q0 -23.5 -19 -40t-45 -16.5h-896q-26 0 -45 16.5t-19 40t19 40.5t45 17h896q26 0 45 -17t19 -40.5z" />
+    <glyph glyph-name="icon_xuanxiangqiayangshi-1" unicode="&#xe6e9;" 
+d="M479 517l-102 -256h47l26 66h113l22 -66h48l-103 256h-51zM461 360l44 113l44 -113h-88zM146 480h88v-219h44v219h91v37h-223v-37zM823 396q21 5 33 22q11 16 11 35v2q0 31 -22 47q-25 19 -62 19h-125v-256h125q46 0 65 14q30 18 30 59q0 30 -15 40q-13 13 -40 18z
+M702 484h70q25 0 40 -7q11 -6 11 -26q0 -18 -11 -29q-7 -7 -40 -7h-70v69zM816 301q-20 -7 -40 -7h-1h-73v80h73q28 0 44 -11q14 -13 15 -33q0 -17 -18 -29zM951 753h-878q-30 0 -51.5 -21.5t-21.5 -51.5v-592q0 -30 21.5 -51.5t51.5 -21.5h878q30 0 51.5 21.5t21.5 51.5
+v592q0 30 -21.5 51.5t-51.5 21.5zM951 125q0 -15 -11 -26t-26 -11h-804q-15 0 -26 11t-11 26v518q0 15 10.5 26t26.5 11h804q16 0 26.5 -11t10.5 -26v-518v0z" />
+    <glyph glyph-name="icon_daxiao-" unicode="&#xe6ea;" 
+d="M747 594v89h-171v-89h-424v-85h424v-82h171v82h125v85h-125zM704 469h-85v171h85v-171zM448 341h-171v-88h-125v-86h125v-82h171v82h424v86h-424v88zM405 128h-85v171h85v-171z" />
+    <glyph glyph-name="icon_qiehuanweidu-" unicode="&#xe6eb;" 
+d="M966 258h-917h-1q-13 0 -26 -9t-18 -21q-4 -9 -4 -19q0 -19 14 -33l289 -290q15 -14 35 -14t33 14q15 15 15 34.5t-15 33.5l-207 207h801q20 1 34 15t14 34v1q0 19 -13.5 33t-33.5 14v0zM49 558h917q33 0 45 29q3 9 3 18v1v0q0 20 -14 34l-241 242q-14 14 -34 14t-34 -14
+q-14 -15 -14 -35t14 -33l159 -159h-801q-20 0 -34 -14.5t-14.5 -34t14 -34t34.5 -14.5z" />
+    <glyph glyph-name="icon_luoxuanfenxibiao-" unicode="&#xe6ec;" horiz-adv-x="1025" 
+d="M951 859h-878q-30 0 -51.5 -21.5t-21.5 -51.5v-804q0 -30 21.5 -51.5t51.5 -21.5h878q30 0 51.5 21.5t21.5 51.5v804q0 30 -21.5 51.5t-51.5 21.5zM858 475q-15 1 -30 5l-141 -251q42 -33 42 -86q0 -45 -31.5 -77t-76.5 -32t-77 32t-32 77q0 25 12 48l-194 167
+q-26 -19 -59 -19q-13 0 -28 4l-66 -118q23 -24 23 -55q0 -33 -24 -57t-58 -24t-57.5 24t-23.5 57.5t23.5 57.5t57.5 24q2 0 18 -4l66 118q-14 13 -23.5 34.5t-9.5 40.5q0 42 30 71.5t72 29.5t72 -29.5t30 -71.5q0 -24 -12 -47l193 -166q12 10 31.5 17t35.5 7q11 0 23 -3
+l140 250q-23 16 -39 47t-16 58q0 54 38 91.5t91.5 37.5t91 -37.5t37.5 -91t-37.5 -91.5t-91.5 -38z" />
+  </font>
+</defs></svg>
diff --git a/dist/font/iconfont.ttf b/dist/font/iconfont.ttf
new file mode 100644
index 000000000..11634db76
Binary files /dev/null and b/dist/font/iconfont.ttf differ
diff --git a/dist/font/iconfont.woff b/dist/font/iconfont.woff
new file mode 100644
index 000000000..f55cb72fa
Binary files /dev/null and b/dist/font/iconfont.woff differ
diff --git a/src/less/base/third/ztree/img/line_conn.gif b/dist/icon/line_conn.gif
similarity index 100%
rename from src/less/base/third/ztree/img/line_conn.gif
rename to dist/icon/line_conn.gif
diff --git a/src/less/base/third/ztree/img/loading.gif b/dist/icon/loading.gif
similarity index 100%
rename from src/less/base/third/ztree/img/loading.gif
rename to dist/icon/loading.gif
diff --git a/dist/icon/tree-collapse-1.png b/dist/icon/tree-collapse-1.png
new file mode 100644
index 000000000..2eb16bf2a
Binary files /dev/null and b/dist/icon/tree-collapse-1.png differ
diff --git a/dist/icon/tree-collapse-2.png b/dist/icon/tree-collapse-2.png
new file mode 100644
index 000000000..685c49c30
Binary files /dev/null and b/dist/icon/tree-collapse-2.png differ
diff --git a/dist/icon/tree-collapse-3.png b/dist/icon/tree-collapse-3.png
new file mode 100644
index 000000000..af57c458f
Binary files /dev/null and b/dist/icon/tree-collapse-3.png differ
diff --git a/dist/icon/tree-collapse-4.png b/dist/icon/tree-collapse-4.png
new file mode 100644
index 000000000..1b20faa12
Binary files /dev/null and b/dist/icon/tree-collapse-4.png differ
diff --git a/dist/icon/tree-expand-1.png b/dist/icon/tree-expand-1.png
new file mode 100644
index 000000000..b92d64cef
Binary files /dev/null and b/dist/icon/tree-expand-1.png differ
diff --git a/dist/icon/tree-expand-2.png b/dist/icon/tree-expand-2.png
new file mode 100644
index 000000000..78b245342
Binary files /dev/null and b/dist/icon/tree-expand-2.png differ
diff --git a/dist/icon/tree-expand-3.png b/dist/icon/tree-expand-3.png
new file mode 100644
index 000000000..b6bd4b1f5
Binary files /dev/null and b/dist/icon/tree-expand-3.png differ
diff --git a/dist/icon/tree-expand-4.png b/dist/icon/tree-expand-4.png
new file mode 100644
index 000000000..835c2591e
Binary files /dev/null and b/dist/icon/tree-expand-4.png differ
diff --git a/dist/icon/tree-vertical-line-1.png b/dist/icon/tree-vertical-line-1.png
new file mode 100644
index 000000000..89d2825fe
Binary files /dev/null and b/dist/icon/tree-vertical-line-1.png differ
diff --git a/dist/icon/tree-vertical-line-2.png b/dist/icon/tree-vertical-line-2.png
new file mode 100644
index 000000000..643856eb7
Binary files /dev/null and b/dist/icon/tree-vertical-line-2.png differ
diff --git a/dist/icon/tree-vertical-line-3.png b/dist/icon/tree-vertical-line-3.png
new file mode 100644
index 000000000..365a2df1f
Binary files /dev/null and b/dist/icon/tree-vertical-line-3.png differ
diff --git a/dist/icon/tree-vertical-line-4.png b/dist/icon/tree-vertical-line-4.png
new file mode 100644
index 000000000..eb9fac960
Binary files /dev/null and b/dist/icon/tree-vertical-line-4.png differ
diff --git a/dist/icon/tree-vertical-line-5.png b/dist/icon/tree-vertical-line-5.png
new file mode 100644
index 000000000..8b21347e9
Binary files /dev/null and b/dist/icon/tree-vertical-line-5.png differ
diff --git a/src/less/base/third/ztree/img/zTreeStandard.gif b/dist/icon/zTreeStandard.gif
similarity index 100%
rename from src/less/base/third/ztree/img/zTreeStandard.gif
rename to dist/icon/zTreeStandard.gif
diff --git a/src/less/base/third/ztree/img/zTreeStandard.png b/dist/icon/zTreeStandard.png
similarity index 100%
rename from src/less/base/third/ztree/img/zTreeStandard.png
rename to dist/icon/zTreeStandard.png
diff --git a/dist/widget.css b/dist/widget.css
new file mode 100644
index 000000000..e7217f5dc
--- /dev/null
+++ b/dist/widget.css
@@ -0,0 +1,1584 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement-block {
+  background: #e85050;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement .arrangement-helper {
+  border: 1px solid #d4dadd;
+  background: #009de3;
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-block {
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-drop-container {
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-drop-container .arrangement-drop-region {
+  overflow: hidden;
+}
+.bi-arrangement .arrangement-drop-container .drop-devider {
+  z-index: 1000000001;
+  background: #009de3;
+}
+.bi-arrangement .arrangement-drop-container .top-left,
+.bi-arrangement .arrangement-drop-container .top-right,
+.bi-arrangement .arrangement-drop-container .bottom-left,
+.bi-arrangement .arrangement-drop-container .bottom-right,
+.bi-arrangement .arrangement-drop-container .top-left-second,
+.bi-arrangement .arrangement-drop-container .top-right-second,
+.bi-arrangement .arrangement-drop-container .bottom-left-second,
+.bi-arrangement .arrangement-drop-container .bottom-right-second,
+.bi-arrangement .arrangement-drop-container .top-center,
+.bi-arrangement .arrangement-drop-container .bottom-center,
+.bi-arrangement .arrangement-drop-container .left-center,
+.bi-arrangement .arrangement-drop-container .right-center,
+.bi-arrangement .arrangement-drop-container .top-center-second,
+.bi-arrangement .arrangement-drop-container .bottom-center-second,
+.bi-arrangement .arrangement-drop-container .left-center-second,
+.bi-arrangement .arrangement-drop-container .right-center-second {
+  z-index: 1000000001;
+  background: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement-droppable {
+  background: #d8f3fe;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+  z-index: 100000;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-icon-combo.bi-combo-popup .bi-icon-combo-trigger .b-font:before {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-adapt-editor .adapt-editor-text {
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
+.bi-search-editor {
+  border: 1px solid #d4dadd;
+}
+.bi-search-editor .close-font {
+  font-size: 20px;
+}
+.bi-search-editor .search-font {
+  font-size: 20px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
+.bi-small-search-editor .bi-editor {
+  font-size: 12px;
+}
+.bi-small-search-editor .bi-editor .bi-input {
+  font-size: 12px;
+}
+.bi-small-search-editor .bi-editor .bi-label {
+  font-size: 12px;
+}
+.bi-small-search-editor .close-font {
+  font-size: 18px;
+}
+.bi-small-search-editor .search-font {
+  font-size: 18px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sign-initial-editor .sign-initial-editor-text {
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sign-style-editor .sign-style-editor-text {
+  max-width: 100%;
+  font-size: 12px;
+}
+.bi-sign-style-editor .sign-style-editor-tip {
+  max-width: 100%;
+  font-size: 12px;
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-editor {
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-loading-main-background {
+  background-color: #ffffff;
+  opacity: 0.7;
+  filter: alpha(opacity=70);
+}
+.bi-loading-mask-content .loading-bar-label {
+  font-size: 20px;
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-line-segment-button.active .line-segment-button-line {
+  background: #009de3;
+}
+.bi-line-segment-button.disabled,
+.bi-line-segment-button.disabled:hover,
+.bi-line-segment-button.disabled:active {
+  color: #1a1a1a;
+  background: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-line-segment {
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-helper {
+  background-color: #009de3;
+  font-size: 13px;
+  color: #ffffff;
+  cursor: url('cursor/cursor_drag_hand.cur'), auto;
+  opacity: 0.7;
+}
+.bi-helper.dragging-modify {
+  background: none;
+}
+.bi-helper.dragging-modify .helper-warning {
+  color: #1a1a1a;
+  border: 1px solid #e85050;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar-bar {
+  background: #eaeaea;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  border-radius: 20px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar .progress-bar-label {
+  font-weight: bold;
+  font-family: "微软雅黑";
+  color: #009de3;
+}
+.bi-progress-bar .progress-bar-label.success {
+  color: #0c6d23;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar-processor {
+  background: #009de3;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  border-radius: 20px;
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+.bi-progress-bar-processor.success {
+  background: #58cc7d;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-chooser-popup .color-chooser-popup-title {
+  background: #f4f4f4;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-color-chooser-popup .color-chooser-popup-more {
+  background: #f4f4f4;
+}
+.bi-color-chooser-popup .color-chooser-popup-more:hover {
+  background: #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-chooser-trigger {
+  background: #ffffff;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -webkit-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -moz-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-copy2group-add-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #fff5c1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.copy2_group_search_pane {
+  background: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-picker {
+  background: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item .b-font:before {
+  background-color: #f4f4f4;
+}
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item:disabled,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item.disabled,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item:disabled .b-font:before,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item.disabled .b-font:before {
+  background-color: #ffffff;
+}
+.bi-down-list-combo .bi-down-list-spliter {
+  border-top: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-down-list-popup .bi-down-list-item:hover,
+.bi-down-list-popup .bi-down-list-item.hover {
+  background-color: #f4f4f4;
+}
+.bi-down-list-popup .bi-down-list-item.disabled,
+.bi-down-list-popup .bi-down-list-item.disabled:hover,
+.bi-down-list-popup .bi-down-list-item.disabled:active {
+  background-color: #ffffff;
+}
+.bi-down-list-popup .bi-down-list-item:active {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-down-list-popup .bi-down-list-item .list-item-text {
+  max-width: 203px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sheet-tab-dynamic-button {
+  background: #eaeaea;
+  border-top: 1px solid #d4dadd;
+}
+.bi-sheet-tab-dynamic-button .bi-icon-button-scroll {
+  border: 1px solid #eaeaea;
+}
+.bi-sheet-tab-dynamic-button .bi-icon-button-scroll:hover {
+  border-color: #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-excel-table > div.bottom-right > div > div > table {
+  border-right: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-excel-table-header-cell {
+  font-weight: bold;
+  background-color: #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-file-item {
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-folder-item {
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-nav-button .file-manager-nav-button-text {
+  max-width: 200px;
+  background: #ffffff;
+}
+.bi-file-manager-nav-button .file-manager-nav-button-text.active {
+  background-color: #f4f4f4;
+  color: #808080;
+}
+.bi-file-manager-nav-button .file-manager-nav-button-triangle {
+  z-index: 1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-nav {
+  border-left: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-item {
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-filter-item .filter-item-empty-item {
+  border-top: 1px solid #d4dadd;
+}
+.bi-filter-item .filter-item-empty-item .empty-filter-item-leaf {
+  border: 1px dashed #178cdf;
+  background: #58cc7d;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-expander {
+  min-width: 100%;
+  border-right: 0px;
+  border-bottom: 0px;
+}
+.bi-filter-expander > .filter-item-empty-item {
+  border-top: 0px;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-filter-expander > table {
+  min-width: 100%;
+}
+.bi-filter-expander > table > tbody > tr > td.first-element {
+  width: 20px;
+  border-right: 1px solid #d4dadd !important;
+  border-bottom: 1px solid #d4dadd !important;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-pane {
+  min-width: 100%;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border-top: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+}
+.bi-filter-pane .condition-container {
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-fine-tuning-number-editor {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-fine-tuning-number-editor .top-button {
+  border-left: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-fine-tuning-number-editor .bottom-button {
+  border-left: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-search-edit {
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-symbol-group .symbol-button:hover,
+.bi-formula-symbol-group .symbol-button.hover,
+.bi-formula-symbol-group .symbol-button:active,
+.bi-formula-symbol-group .symbol-button.active {
+  color: #009de3;
+  background-color: #f4f4f4;
+  border: 1px solid #d4dadd;
+}
+.bi-formula-symbol-group .symbol-button {
+  color: #009de3;
+  border: 1px solid #ffffff;
+}
+.symbol-group-column {
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-insert .more-function-button {
+  color: #009de3;
+}
+.bi-formula-insert .bi-formula-field-pane {
+  border-top: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-formula-insert .bi-formula-editor {
+  border-left: 1px solid #d4dadd;
+  border-top: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+}
+.bi-formula-insert .bi-water-mark {
+  font-size: 14px;
+}
+.bi-formula-insert .proxy_div {
+  font-size: 13px;
+  background-color: #009de3;
+  color: #ffffff;
+  opacity: 0.7;
+  cursor: pointer;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-button-text-tree-item:hover,
+.bi-button-text-tree-item.hover {
+  background-color: #f4f4f4;
+}
+.bi-button-text-tree-item.active {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-button-text-tree-item.disabled,
+.bi-button-text-tree-item.disabled:hover,
+.bi-button-text-tree-item.disabled:active {
+  background-color: #ffffff;
+}
+.bi-button-text-tree-item .formula-function-insert-button {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-function-pane .style-inner {
+  border-left: 1px solid #d4dadd;
+  border-top: 1px solid #d4dadd;
+}
+.bi-formula-function-pane .style-top {
+  border-top: 1px solid #d4dadd;
+}
+.bi-formula-function-pane .style-left {
+  border-left: 1px solid #d4dadd;
+}
+.bi-formula-function-pane {
+  background-color: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-field-tree {
+  background-color: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-function-tree {
+  background-color: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-image-button-href .image-button-href-icon-button {
+  z-index: 1;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-image-button-size .image-button-size-button-group {
+  font-size: 12px;
+  color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-upload-image .upload-image-text-button-label {
+  font-size: 14px;
+  color: #c4c6c6;
+}
+.bi-upload-image .upload-image-icon-button {
+  z-index: 1;
+  font-size: 16px;
+  background-color: #ffffff;
+}
+.bi-upload-image .upload-image-delete-label {
+  font-size: 14px;
+  color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-interactive-arrangement .interactive-arrangement-dragtag-line {
+  z-index: 1000000000;
+  background-color: #f07d0a;
+}
+.bi-interactive-arrangement .interactive-arrangement-dragtag-icon {
+  z-index: 1000000000;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-list-label {
+  font-size: 14px;
+}
+.bi-list-label .list-label-button:hover {
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-month-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-move2group-add-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #fff5c1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.move2_group_search_pane {
+  background: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-combo {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-daycard .bi-multidate-inner-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-monthcard .bi-multidate-inner-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-popup .bi-multidate-popup-label {
+  color: #009de3;
+  font-size: 14px;
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-top: 1px solid #eaeaea;
+}
+.bi-multidate-popup .bi-multidate-popup-tab {
+  border-bottom: 1px solid #eaeaea;
+}
+.bi-multidate-popup .bi-multidate-popup-item:active,
+.bi-multidate-popup .bi-multidate-popup-item.active {
+  background-color: #009de3;
+  color: #ffffff;
+  -webkit-border-radius: 2px 2px 0 0;
+  -moz-border-radius: 2px 2px 0 0;
+  border-radius: 2px 2px 0 0;
+}
+.bi-multidate-popup .bi-multidate-popup-button {
+  color: #009de3;
+  font-size: 14px;
+  border-top: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-quartercard .bi-multidate-inner-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-segment .bi-multidate-normal-label {
+  color: #1a1a1a;
+}
+.bi-multidate-segment .bi-multidate-editor {
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-weekcard .bi-multidate-inner-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-yearcard .bi-multidate-inner-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-check-pane .multi-select-continue-select {
+  background-color: #f4f4f4;
+}
+.bi-multi-select-check-pane .multi-select-check-selected {
+  color: #009de3;
+  text-decoration: underline;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-display-list {
+  background-color: #f4f4f4;
+}
+.bi-display-list .display-list-item {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-combo .multi-select-trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-popup-view .multi-select-no-toolbar {
+  color: #c4c6c6;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-search-pane {
+  background: #ffffff;
+}
+.bi-multi-select-search-pane .multi-select-toolbar {
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-check-selected-button {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-string-list .popup-multi-string-list {
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-check-pane {
+  background-color: #f4f4f4;
+}
+.bi-multi-tree-check-pane .multi-tree-continue-select {
+  background-color: #f4f4f4;
+}
+.bi-multi-tree-check-pane .multi-tree-check-selected {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-display {
+  background-color: #f4f4f4;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-combo .multi-select-trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
+.bi-multi-tree-trigger .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+.bi-multi-tree-trigger .trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-popup .popup-view-tree {
+  min-height: 170px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-search-pane {
+  background: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
+.bi-multi-tree-trigger .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+.bi-multi-tree-trigger .trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-check-selected-button .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tree-list-popup {
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-numerical-interval .numerical-interval-small-editor {
+  border-top: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+  -moz-border-radius-topleft: 2px;
+  -webkit-border-top-left-radius: 2px;
+  -moz-border-radius-bottomleft: 2px;
+  -webkit-border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-editor {
+  border-top: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  -moz-border-radius-topright: 2px;
+  -webkit-border-top-right-radius: 2px;
+  -moz-border-radius-bottomright: 2px;
+  -webkit-border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-combo {
+  border: 1px solid #d4dadd;
+  -moz-border-radius-topleft: 2px;
+  -webkit-border-top-left-radius: 2px;
+  -moz-border-radius-bottomleft: 2px;
+  -webkit-border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-combo .bi-icon-combo-trigger .icon-combo-trigger-icon {
+  font-size: 14px;
+}
+.bi-numerical-interval .numerical-interval-small-combo {
+  border: 1px solid #d4dadd;
+  -moz-border-radius-topright: 2px;
+  -webkit-border-top-right-radius: 2px;
+  -moz-border-radius-bottomright: 2px;
+  -webkit-border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-small-combo .bi-icon-combo-trigger .icon-combo-trigger-icon {
+  font-size: 14px;
+}
+.bi-numerical-interval.number-error .bi-input {
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-numerical-interval-popup .numerical-interval-popup-item.hover,
+.bi-numerical-interval-popup .numerical-interval-popup-item:hover {
+  background-color: #f4f4f4;
+}
+.bi-numerical-interval-popup .numerical-interval-popup-item.active,
+.bi-numerical-interval-popup .numerical-interval-popup-item:active {
+  background-color: #f4f4f4;
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-page-table-cell {
+  -webkit-user-select: initial;
+  -khtml-user-select: initial;
+  -moz-user-select: initial;
+  -ms-user-select: initial;
+  -o-user-select: initial;
+  user-select: initial;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-interval-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param0-date-item .param-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param1-date-item .param-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param2-date-item .param-label {
+  color: #808080;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-month-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-season-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-path-chooser .path-chooser-radio {
+  z-index: 1;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-path-region {
+  background: #eaeaea;
+}
+.bi-path-region .path-region-label {
+  z-index: 1;
+  background: #ffffff;
+  border: 1px solid #ffffff;
+}
+.bi-path-region .path-region-label.active {
+  background: #009de3;
+  color: #ffffff;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table-cell {
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table > div > table > thead > tr.odd,
+.bi-preview-table > div > div > div > table > thead > tr.odd {
+  background-color: #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table-header-cell {
+  font-weight: bold;
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-quarter-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-relation-view-item.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-relation-view-region .relation-view-region-container {
+  background: #ffffff;
+  border: 1px solid #d4dadd;
+  z-index: 1;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-relation-view-region .relation-view-region-container.other-package {
+  border: 1px dashed #d4dadd;
+}
+.bi-relation-view-region .relation-view-region-container .relation-view-region-title {
+  border-bottom: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-search-result-pane .search-result-line {
+  border-top: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-searcher {
+  font-size: 13px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-search-segment .search-segment-field-table > .first-element {
+  -webkit-border-radius: 3px 0px 0px 3px;
+  -moz-border-radius: 3px 0px 0px 3px;
+  border-radius: 3px 0px 0px 3px;
+}
+.bi-select-data-search-segment .search-segment-field-table > .last-element {
+  -webkit-border-radius: 0px 3 3px 0px;
+  -moz-border-radius: 0px 3 3px 0px;
+  border-radius: 0px 3 3px 0px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level0-node .select-data-selected-count-label {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level1-node .select-data-selected-count-label {
+  color: #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level0-item .select-data-level0-item-button {
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:hover,
+.bi-select-data-level0-item .select-data-level0-item-button.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:active,
+.bi-select-data-level0-item .select-data-level0-item-button.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:active .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.active .bi-high-light {
+  color: #ffffff;
+}
+.bi-select-data-level0-item .select-data-level0-item-button.disabled,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:hover,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:active {
+  color: #c4c6c6 !important;
+  background-color: #ffffff !important;
+}
+.bi-select-data-level0-item .select-data-level0-item-button.disabled .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:hover .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:active .bi-high-light {
+  color: #c4c6c6 !important;
+}
+.bi-select-data-level0-item .select-data-top-line,
+.bi-select-data-level0-item .select-data-bottom-line {
+  background-color: #009de3;
+}
+.bi-select-data-level0-item.select-data-item-top .select-data-level0-item-button {
+  -moz-border-radius-topleft: 0;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -webkit-border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.bi-select-data-level0-item.select-data-item-bottom .select-data-level0-item-button {
+  -moz-border-radius-bottomleft: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -moz-border-radius-bottomright: 0;
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level1-item .select-data-level1-item-button {
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:hover,
+.bi-select-data-level1-item .select-data-level1-item-button.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:active,
+.bi-select-data-level1-item .select-data-level1-item-button.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:active .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.active .bi-high-light {
+  color: #ffffff;
+}
+.bi-select-data-level1-item .select-data-level1-item-button.disabled,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:hover,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:active {
+  color: #c4c6c6 !important;
+  background-color: #ffffff !important;
+}
+.bi-select-data-level1-item .select-data-level1-item-button.disabled .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:hover .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:active .bi-high-light {
+  color: #c4c6c6 !important;
+}
+.bi-select-data-level1-item .select-data-top-line,
+.bi-select-data-level1-item .select-data-bottom-line {
+  background-color: #009de3;
+}
+.bi-select-data-level1-item.select-data-item-top .select-data-level1-item-button {
+  -moz-border-radius-topleft: 0;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -webkit-border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.bi-select-data-level1-item.select-data-item-bottom .select-data-level1-item-button {
+  -moz-border-radius-bottomleft: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -moz-border-radius-bottomright: 0;
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-database-table {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+  background: #ffffff;
+}
+.bi-database-table.active {
+  background: #009de3;
+  color: #ffffff;
+}
+.bi-database-table .table-name-text {
+  max-width: 300px;
+}
+.bi-database-table .table-font {
+  font-size: 16px;
+}
+.bi-database-table .table-conn-label1 {
+  background-color: #009de3;
+}
+.bi-database-table .table-conn-label2 {
+  background-color: #4fc1e9;
+}
+.bi-database-table .table-conn-label3 {
+  background-color: #48cfad;
+}
+.bi-database-table .table-conn-label4 {
+  background-color: #57cb7c;
+}
+.bi-database-table .table-conn-label5 {
+  background-color: #a0d468;
+}
+.bi-database-table .table-conn-label6 {
+  background-color: #fbaf4f;
+}
+.bi-database-table .table-conn-label7 {
+  background-color: #fc6e51;
+}
+.bi-database-table .table-conn-label8 {
+  background-color: #ed5565;
+}
+.bi-database-table .table-conn-label9 {
+  background-color: #ac92ec;
+}
+.bi-database-table .table-conn-label10 {
+  background-color: #5d9cec;
+}
+.bi-database-table.table-selected1.active {
+  background-color: #009de3;
+}
+.bi-database-table.table-selected2.active {
+  background-color: #4fc1e9;
+}
+.bi-database-table.table-selected3.active {
+  background-color: #48cfad;
+}
+.bi-database-table.table-selected4.active {
+  background-color: #57cb7c;
+}
+.bi-database-table.table-selected5.active {
+  background-color: #a0d468;
+}
+.bi-database-table.table-selected6.active {
+  background-color: #fbaf4f;
+}
+.bi-database-table.table-selected7.active {
+  background-color: #fc6e51;
+}
+.bi-database-table.table-selected8.active {
+  background-color: #ed5565;
+}
+.bi-database-table.table-selected9.active {
+  background-color: #ac92ec;
+}
+.bi-database-table.table-selected10.active {
+  background-color: #5d9cec;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-selecttree-combo .selecttree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-dynamic-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-dynamic-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-list-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-list-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-tree-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-tree-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-single-slider .slider-editor-button .sign-editor-text:hover {
+  border: 1px solid #d4dadd;
+}
+.bi-single-slider .slider-editor-button .bi-editor {
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-single-slider-slider {
+  cursor: url('cursor/cursor_left_right.cur'), auto;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-slider-track .background-track {
+  background-color: #f4f4f4;
+  -webkit-border-radius: 12px;
+  -moz-border-radius: 12px;
+  border-radius: 12px;
+}
+.bi-slider-track .gray-track {
+  background: #cccccc;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
+.bi-slider-track .blue-track {
+  background: #009de3;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-singletree-combo .singletree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-singletree-combo .bi-singletree-popup .singletree-toolbar {
+  color: #c4c6c6;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sortable-table .sortable_table_drag_clone {
+  background: #d8f2fd;
+  top: 0px;
+  opacity: 0.5;
+}
+.bi-sortable-table .drag-header {
+  cursor: move;
+}
+.bi-sortable-table .insert-help-line {
+  border-right: 3px dashed #009de3;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-area .text-area-editor-text-button-label {
+  font-size: 16px;
+  color: #c4c6c6;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-toolbar-align-chooser .align-chooser-button:hover {
+  background-color: #c4c6c6;
+}
+.bi-text-toolbar-align-chooser .align-chooser-button.active {
+  background-color: #c4c6c6;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-toolbar {
+  background: #eaeaea;
+}
+.bi-text-toolbar .text-toolbar-button {
+  font-size: 16px;
+}
+.bi-text-toolbar .text-toolbar-size-chooser-trigger {
+  background: #ffffff;
+  font-size: 12px;
+}
+.bi-text-toolbar .text-toolbar-size-chooser-trigger a {
+  font-size: 12px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param-time-interval.time-error .bi-input {
+  color: #e85050;
+}
+.bi-param-time-interval.time-error .sign-editor-text {
+  color: #e85050;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-time-setting-day .operator-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-time-setting-hour .operator-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tree-label {
+  font-size: 14px;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-web-page .web-page-button {
+  z-index: 1;
+  font-size: 14px;
+  background-color: #ffffff;
+}
+.bi-web-page .web-page-text-button-label {
+  font-size: 16px;
+  color: #c4c6c6;
+}
+.bi-web-page .web-page-delete-label {
+  font-size: 14px;
+  color: #1a1a1a;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-popup .year-popup-navigation {
+  border-top: 1px solid #eaeaea;
+  line-height: 30px;
+  color: #009de3;
+}
+.bi-year-popup .year-popup-navigation > .center-element {
+  border-left: 1px solid #eaeaea;
+}
+.bi-year-popup .year-popup-navigation > .first-element {
+  border-left: none;
+}
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/dist/widget.js b/dist/widget.js
new file mode 100644
index 000000000..5b882d9f8
--- /dev/null
+++ b/dist/widget.js
@@ -0,0 +1,30146 @@
+/**
+ * 普通控件
+ *
+ * @class BI.ParamPopupView
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.ParamPopupView = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ParamPopupView.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    dateConfig: function(){
+
+    },
+
+    _init: function () {
+        BI.ParamPopupView.superclass._init.apply(this, arguments);
+        var self = this;
+
+        this.radioGroup = BI.createWidget({
+            type: "bi.button_group",
+            chooseType: 0,
+            items: this.dateConfig(),
+            layouts: [{
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.vertical",
+                    vgap: 5
+                }],
+                vgap: 5,
+                hgap: 5
+            }]
+        });
+
+        this.radioGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.ParamPopupView.EVENT_CHANGE);
+        });
+        this.popup = BI.createWidget({
+            type: 'bi.multi_popup_view',
+            element: this,
+            el: this.radioGroup,
+            minWidth: 310,
+            stopPropagation: false
+        });
+
+        this.popup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function () {
+            self.fireEvent(BI.ParamPopupView.EVENT_CONFIRM);
+        });
+
+    },
+
+    setValue: function (v) {
+        this.radioGroup.setValue(v.type);
+        BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+            if (button.isSelected()) {
+                button.setEnable(true);
+                button.setInputValue(v.value);
+            } else {
+                button.setEnable(false);
+            }
+        });
+    },
+
+    getValue: function () {
+        var button = this.radioGroup.getSelectedButtons()[0];
+        var type = button.getValue(), value = button.getInputValue();
+        return {
+            type: type,
+            value: value
+        }
+    },
+
+    getCalculationValue: function () {
+        var valueObject = this.getValue();
+        var type = valueObject.type, value = valueObject.value;
+        var fPrevOrAfter = value.foffset === 0 ? -1 : 1;
+        var sPrevOrAfter = value.soffset === 0 ? -1 : 1;
+        var start, end;
+        start = end = new Date();
+        var ydate = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), new Date().getMonth(), new Date().getDate());
+        switch (type) {
+            case BICst.YEAR:
+                start = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), 0, 1);
+                end = new Date(start.getFullYear(), 11, 31);
+                break;
+            case BICst.YEAR_QUARTER:
+                ydate = new Date().getOffsetQuarter(ydate, sPrevOrAfter * value.svalue);
+                start = ydate.getQuarterStartDate();
+                end = ydate.getQuarterEndDate();
+                break;
+            case BICst.YEAR_MONTH:
+                ydate = new Date().getOffsetMonth(ydate, sPrevOrAfter * value.svalue);
+                start = new Date(ydate.getFullYear(), ydate.getMonth(), 1);
+                end  = new Date(ydate.getFullYear(), ydate.getMonth(), (ydate.getLastDateOfMonth()).getDate());
+                break;
+            case BICst.YEAR_WEEK:
+                start = ydate.getOffsetDate(sPrevOrAfter * 7 * value.svalue);
+                end = start.getOffsetDate(7);
+                break;
+            case BICst.YEAR_DAY:
+                start = ydate.getOffsetDate(sPrevOrAfter * value.svalue);
+                end = start.getOffsetDate(1);
+                break;
+            case BICst.MONTH_WEEK:
+                var mdate = new Date().getOffsetMonth(new Date(), fPrevOrAfter * value.fvalue);
+                start = mdate.getOffsetDate(sPrevOrAfter * 7 * value.svalue);
+                end = start.getOffsetDate(7);
+                break;
+            case BICst.MONTH_DAY:
+                var mdate = new Date().getOffsetMonth(new Date(), fPrevOrAfter * value.fvalue);
+                start = mdate.getOffsetDate(sPrevOrAfter * value.svalue);
+                end = start.getOffsetDate(1);
+                break;
+        }
+        return {
+            start: start,
+            end: end
+        };
+    },
+
+    resetWidth: function(w){
+        this.popup.resetWidth(w);
+    },
+
+    resetHeight: function(h){
+        this.popup.resetHeight(h);
+    }
+});
+BI.ParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.ParamPopupView.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.param_popup_view", BI.ParamPopupView);/**
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTableTreeNumber
+ * @extends BI.Widget
+ */
+BI.SequenceTableTreeNumber = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableTreeNumber.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table-tree-number",
+            isNeedFreeze: false,
+            startSequence: 1,//开始的序号
+            scrollTop: 0,
+            headerRowSize: 25,
+            rowSize: 25,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableTreeNumber.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.vCurr = 1;
+        this.hCurr = 1;
+        this.tasks = [];
+        this.renderedCells = [];
+        this.renderedKeys = [];
+
+        this.header = BI.createWidget({
+            type: "bi.table_style_cell",
+            cls: "sequence-table-title-cell",
+            styleGetter: o.headerCellStyleGetter,
+            text: BI.i18nText("BI-Number_Index")
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            width: 60,
+            scrollable: false
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.container]
+        });
+
+        this.layout = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.header,
+                height: this._getHeaderHeight()
+            }, {
+                el: this.scrollContainer
+            }]
+        });
+        //缓存第一行对应的序号
+        this.start = this.options.startSequence;
+        this.cache = {};
+        this._nextState();
+
+        this._populate();
+    },
+
+    _getNextSequence: function (nodes) {
+        var self = this;
+        var start = this.start;
+        var cnt = this.start;
+
+        function track(node) {
+            self.cache[node.text || node.value] = cnt++;
+        }
+
+        BI.each(nodes, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    if (index === 0) {
+                        if (self.cache[child.text || child.value]) {
+                            start = cnt = self.cache[child.text || child.value];
+                        }
+                    }
+                    track(child)
+                });
+            }
+        });
+        this.start = cnt;
+        return start;
+    },
+
+    _getStart: function (nodes) {
+        var self = this;
+        var start = this.start;
+        BI.each(nodes, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    if (index === 0) {
+                        if (self.cache[child.text || child.value]) {
+                            start = self.cache[child.text || child.value];
+                        }
+                    }
+                });
+            }
+        });
+        return start;
+    },
+
+    _formatNumber: function (nodes) {
+        var self = this, o = this.options;
+        var result = [];
+        var count = this._getStart(nodes);
+
+        function getLeafCount(node) {
+            var cnt = 0;
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    cnt += getLeafCount(child);
+                });
+                if (/**node.children.length > 1 && **/BI.isNotEmptyArray(node.values)) {
+                    cnt++;
+                }
+            } else {
+                cnt++;
+            }
+            return cnt;
+        }
+
+        var start = 0, top = 0;
+        BI.each(nodes, function (i, node) {
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    var cnt = getLeafCount(child);
+                    result.push({
+                        text: count++,
+                        start: start,
+                        top: top,
+                        cnt: cnt,
+                        index: index,
+                        height: cnt * o.rowSize
+                    });
+                    start += cnt;
+                    top += cnt * o.rowSize;
+                });
+                if (BI.isNotEmptyArray(node.values)) {
+                    result.push({
+                        text: BI.i18nText("BI-Summary_Values"),
+                        start: start++,
+                        top: top,
+                        cnt: 1,
+                        isSummary: true,
+                        height: o.rowSize
+                    });
+                    top += o.rowSize;
+                }
+            }
+        });
+        return result;
+    },
+
+    _layout: function () {
+        var self = this, o = this.options;
+        var headerHeight = this._getHeaderHeight();
+        var items = this.layout.attr("items");
+        if (o.isNeedFreeze === false) {
+            items[0].height = 0;
+        } else if (o.isNeedFreeze === true) {
+            items[0].height = headerHeight;
+        }
+        this.layout.attr("items", items);
+        this.layout.resize();
+        this.scrollContainer.element.scrollTop(o.scrollTop);
+    },
+
+    _getHeaderHeight: function () {
+        var o = this.options;
+        return o.headerRowSize * (o.crossHeader.length + (o.header.length > 0 ? 1 : 0));
+    },
+
+    _nextState: function () {
+        var o = this.options;
+        this._getNextSequence(o.items);
+    },
+
+    _prevState: function () {
+        var self = this, o = this.options;
+        var firstChild;
+        BI.some(o.items, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                return BI.some(node.children, function (j, child) {
+                    firstChild = child;
+                    return true;
+                });
+            }
+        });
+        if (firstChild && BI.isNotEmptyObject(this.cache)) {
+            this.start = this.cache[firstChild.text || firstChild.value];
+        } else {
+            this.start = 1;
+        }
+        this._nextState();
+    },
+
+    _getMaxScrollTop: function (numbers) {
+        var cnt = 0;
+        BI.each(numbers, function (i, number) {
+            cnt += number.cnt;
+        });
+        return Math.max(0, cnt * this.options.rowSize - (this.options.height - this._getHeaderHeight()) + BI.DOM.getScrollWidth());
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+
+        var renderedCells = [], renderedKeys = [];
+        var numbers = this._formatNumber(o.items);
+        var intervalTree = BI.PrefixIntervalTree.uniform(numbers.length, 0);
+        BI.each(numbers, function (i, number) {
+            intervalTree.set(i, number.height);
+        });
+        var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop(numbers));
+        var index = intervalTree.greatestLowerBound(scrollTop);
+        var offsetTop = -(scrollTop - (index > 0 ? intervalTree.sumTo(index - 1) : 0));
+        var height = offsetTop;
+        var bodyHeight = o.height - this._getHeaderHeight();
+        while (height < bodyHeight && index < numbers.length) {
+            renderedKeys.push(index);
+            offsetTop += numbers[index].height;
+            height += numbers[index].height;
+            index++;
+        }
+
+        BI.each(renderedKeys, function (i, key) {
+            var index = BI.deepIndexOf(self.renderedKeys, key);
+            if (index > -1) {
+                if (numbers[key].height !== self.renderedCells[index]._height) {
+                    self.renderedCells[index]._height = numbers[key].height;
+                    self.renderedCells[index].el.setHeight(numbers[key].height);
+                }
+                if (numbers[key].top !== self.renderedCells[index].top) {
+                    self.renderedCells[index].top = numbers[key].top;
+                    self.renderedCells[index].el.element.css("top", numbers[key].top + "px");
+                }
+                renderedCells.push(self.renderedCells[index]);
+            } else {
+                var child = BI.createWidget(BI.extend({
+                    type: "bi.table_style_cell",
+                    cls: "sequence-table-number-cell",
+                    width: 60,
+                    styleGetter: numbers[key].isSummary === true ? function () {
+                        return o.summaryCellStyleGetter(true);
+                    } : function (key) {
+                        return function () {
+                            return o.sequenceCellStyleGetter(key);
+                        }
+                    }(numbers[key].index)
+                }, numbers[key]));
+                renderedCells.push({
+                    el: child,
+                    left: 0,
+                    top: numbers[key].top,
+                    _height: numbers[key].height
+                });
+            }
+        });
+
+        //已存在的, 需要添加的和需要删除的
+        var existSet = {}, addSet = {}, deleteArray = [];
+        BI.each(renderedKeys, function (i, key) {
+            if (BI.deepContains(self.renderedKeys, key)) {
+                existSet[i] = key;
+            } else {
+                addSet[i] = key;
+            }
+        });
+        BI.each(this.renderedKeys, function (i, key) {
+            if (BI.deepContains(existSet, key)) {
+                return;
+            }
+            if (BI.deepContains(addSet, key)) {
+                return;
+            }
+            deleteArray.push(i);
+        });
+        BI.each(deleteArray, function (i, index) {
+            self.renderedCells[index].el.destroy();
+        });
+        var addedItems = [];
+        BI.each(addSet, function (index) {
+            addedItems.push(renderedCells[index])
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: addedItems
+        });
+        this.renderedCells = renderedCells;
+        this.renderedKeys = renderedKeys;
+
+        this.container.setHeight(intervalTree.sumUntil(numbers.length));
+    },
+
+    _restore: function () {
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+    },
+
+    _populate: function () {
+        var self = this;
+        BI.each(this.tasks, function (i, task) {
+            task.apply(self);
+        });
+        this.tasks = [];
+        this.header.populate();
+        this._layout();
+        this._calculateChildrenToRender();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        if (this.options.scrollTop !== scrollTop) {
+            this.options.scrollTop = scrollTop;
+            this.scrollContainer.element.scrollTop(scrollTop);
+        }
+    },
+
+    getVerticalScroll: function () {
+        return this.options.scrollTop;
+    },
+
+    setVPage: function (v) {
+        if (v <= 1) {
+            this.cache = {};
+            this.start = this.options.startSequence;
+            this._restore();
+            this.tasks.push(this._nextState);
+        } else if (v === this.vCurr + 1) {
+            this.tasks.push(this._nextState);
+        } else if (v === this.vCurr - 1) {
+            this.tasks.push(this._prevState);
+        }
+        this.vCurr = v;
+    },
+
+    setHPage: function (v) {
+        if (v !== this.hCurr) {
+            this.tasks.push(this._prevState);
+        }
+        this.hCurr = v;
+    },
+
+    restore: function () {
+        this._restore();
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        if (items && items !== this.options.items) {
+            o.items = items;
+            this._restore();
+            this.tasks.push(this._prevState);
+        }
+        if (header && header !== this.options.header) {
+            o.header = header;
+        }
+        if (crossItems && crossItems !== this.options.crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader && crossHeader !== this.options.crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        this._populate();
+    }
+});
+$.shortcut('bi.sequence_table_tree_number', BI.SequenceTableTreeNumber);/**
+ * 自适应布局
+ *
+ * 1、resize
+ * 2、吸附
+ * 3、当前组件在最上方
+ * 4、可以撤销
+ * 5、上下之间插入组件
+ *
+ * Created by GUY on 2016/2/23.
+ * @class BI.AdaptiveArrangement
+ * @extends BI.Widget
+ */
+BI.AdaptiveArrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.AdaptiveArrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-adaptive-arrangement",
+            resizable: true,
+            isNeedReLayout: true,
+            isNeedResizeContainer: true,
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.AdaptiveArrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.arrangement",
+            element: this,
+            isNeedReLayout: o.isNeedReLayout,
+            layoutType: o.layoutType,
+            items: o.items
+        });
+        if (o.isNeedResizeContainer) {
+
+            var isResizing = false;
+            var height;
+            var interval;
+            var resize = function (e, ui) {
+                if (isResizing) {
+                    return;
+                }
+                isResizing = true;
+                height = ui.size.height;
+                interval = setInterval(function () {
+                    height += 40;
+                    self.arrangement.setContainerSize({
+                        width: ui.size.width,
+                        height: height
+                    });
+                    self.arrangement.scrollTo(height);
+                }, 500);
+            };
+            this.arrangement.container.element.resizable({
+                handles: "s",
+                minWidth: 100,
+                minHeight: 20,
+                helper: "bi-resizer",
+                autoHide: true,
+                resize: function (e, ui) {
+                    if (ui.size.height >= self.arrangement.container.element.height()) {
+                        resize(e, ui);
+                    } else {
+                        interval && clearInterval(interval);
+                    }
+                },
+                stop: function (e, ui) {
+                    var size = ui.size;
+                    if (isResizing) {
+                        size.height = height;
+                    }
+                    self.arrangement.setContainerSize(ui.size);
+                    isResizing = false;
+                    interval && clearInterval(interval);
+                    self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+                }
+            });
+            this._setLayoutType(o.layoutType);
+        }
+        this.zIndex = 0;
+        BI.each(o.items, function (i, item) {
+            self._initResizable(item.el);
+        });
+
+        this.element.click(function (e) {
+            BI.each(self.getAllRegions(), function (i, region) {
+                if (!region.el.element.__isMouseInBounds__(e)) {
+                    region.el.element.removeClass("selected");
+                }
+            });
+        });
+        BI.ResizeDetector.addResizeListener(this, function () {
+            self.arrangement.resize();
+            self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+        });
+    },
+
+    _isEqual: function () {
+        return this.arrangement._isEqual.apply(this.arrangement, arguments);
+    },
+
+    _initResizable: function (item) {
+        var self = this, o = this.options;
+        item.element.css("zIndex", ++this.zIndex);
+        item.element.mousedown(function () {
+            if (!item.element.hasClass("selected")) {
+                item.element.css("zIndex", ++self.zIndex);
+                BI.each(self.getAllRegions(), function (i, region) {
+                    region.el.element.removeClass("selected");
+                });
+                item.element.addClass("selected");
+            }
+        });
+        o.resizable && item.element.resizable({
+            handles: "e, s, se",
+            minWidth: 20,
+            minHeight: 20,
+            autoHide: true,
+            helper: "bi-resizer",
+            start: function () {
+                item.element.css("zIndex", ++self.zIndex);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE);
+            },
+            resize: function (e, ui) {
+                // self._resize(item.attr("id"), ui.size);
+                self._resize(item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, item.attr("id"), ui.size);
+            },
+            stop: function (e, ui) {
+                self._stopResize(item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+            }
+        });
+    },
+
+    _resize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.setRegionSize(name, size);
+                break;
+        }
+    },
+
+    _stopResize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                this.setRegionSize(name, {
+                    width: size.width,
+                    height: size.height
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                this.setRegionSize(name, size);
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.setRegionSize(name, size);
+                break;
+        }
+    },
+
+    //检查宽高是否规范
+    _checkRegionSize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var newSize = {};
+                var leftid, rightid, topid, bottomid;
+                var region = this.getRegionByName(name);
+                var rs = this.arrangement._getInDirectRelativeRegions(name, ["right"]).right;
+                var bs = this.arrangement._getInDirectRelativeRegions(name, ["bottom"]).bottom;
+                if (rs.left.length > 0) {
+                    topid = BI.first(rs.left).id;
+                    bottomid = BI.last(rs.left).id;
+                }
+                if (bs.top.length > 0) {
+                    leftid = BI.first(bs.top).id;
+                    rightid = BI.last(bs.top).id;
+                }
+                if (this.arrangement._isEqual(region.width, size.width)) {
+                    topid = name;
+                    bottomid = name;
+                }
+                if (this.arrangement._isEqual(region.height, size.height)) {
+                    leftid = name;
+                    rightid = name;
+                }
+                var tops = topid ? this.getDirectRelativeRegions(topid, ["top"]).top : [];
+                var bottoms = bottomid ? this.getDirectRelativeRegions(bottomid, ["bottom"]).bottom : [];
+                var lefts = leftid ? this.getDirectRelativeRegions(leftid, ["left"]).left : [];
+                var rights = rightid ? this.getDirectRelativeRegions(rightid, ["right"]).right : [];
+                if (region.width !== size.width) {
+                    if (rights.length === 0) {//最右边的组件不能调整宽度
+                        newSize.width = region.width;
+                    } else {
+                        var finded = BI.find(tops.concat(bottoms), function (i, r) {
+                            r = self.getRegionByName(r.id);
+                            return Math.abs(size.width + region.left - (r.left + r.width)) <= 3;
+                        });
+                        if (finded) {
+                            finded = this.getRegionByName(finded.id);
+                            newSize.width = finded.left + finded.width - region.left;
+                        } else {
+                            newSize.width = size.width;
+                        }
+                    }
+                } else {
+                    newSize.width = size.width;
+                }
+                if (region.height !== size.height) {
+                    if (bottoms.length === 0) {
+                        newSize.height = region.height;
+                    } else {
+                        var finded = BI.find(lefts.concat(rights), function (i, r) {
+                            r = self.getRegionByName(r.id);
+                            return Math.abs(size.height + region.top - (r.top + r.height)) <= 3;
+                        });
+                        if (finded) {
+                            finded = this.getRegionByName(finded.id);
+                            newSize.height = finded.top + finded.height - region.top;
+                        } else {
+                            newSize.height = size.height;
+                        }
+                    }
+                } else {
+                    newSize.height = size.height;
+                }
+                return newSize;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                return size;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                return size;
+        }
+    },
+
+    _getScrollOffset: function () {
+        return this.arrangement._getScrollOffset();
+    },
+
+    _setLayoutType: function (type) {
+        try {
+            //BI.nextTick(function () {
+            switch (type) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "");
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "-1");
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "-1");
+                    break;
+            }
+            this.arrangement.container.element.resizable("option", "disabled", type === BI.Arrangement.LAYOUT_TYPE.FREE);
+            //});
+        } catch (e) {
+
+        }
+    },
+
+    getClientWidth: function () {
+        return this.arrangement.getClientWidth();
+    },
+
+    getClientHeight: function () {
+        return this.arrangement.getClientHeight();
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        return this.arrangement.getDirectRelativeRegions(name, direction);
+    },
+
+    addRegion: function (region, position) {
+        this._initResizable(region.el);
+        var self = this, flag;
+        var old = this.arrangement.getAllRegions();
+        if (BI.isNotNull(this.position)) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    var type = this.position.type;
+                    var current = this.position.region;
+                    switch (type) {
+                        case "top-gap":
+                            var t = this.arrangement._getEquivalentRelativeRegions(current.id, ["top"])[0];
+                            current = this.getRegionByName(t.id);
+                            break;
+                        case "bottom-gap":
+                            break;
+                    }
+                    var id = BI.UUID();
+                    var insert = this.position.insert;
+                    if (insert.height > 0) {
+                        var clone = this.arrangement._cloneRegion();
+                        //找到最下面的组件
+                        var occupied = this.arrangement._getRegionOccupied();
+                        var bottomRegions = [];
+                        BI.each(clone, function (i, region) {
+                            if (self.arrangement._isEqual(region.top + region.height, occupied.top + occupied.height)) {
+                                bottomRegions.push(region);
+                            }
+                        });
+                        var bs = this.arrangement._getInDirectRelativeRegions(current.id, ["bottom"]).bottom;
+                        var seen = [current.id];
+                        var bottoms = bs.bottom;
+                        var occ = this.arrangement._getRegionOccupied(bottoms);
+                        clone[id] = BI.extend({}, region, {
+                            left: occ.left,
+                            width: occ.width,
+                            top: current.top + current.height,
+                            height: insert.height
+                        });
+                        while (bottoms.length > 0) {
+                            BI.each(bottoms, function (i, bottom) {
+                                seen.push(bottom.id);
+                                var r = self.getRegionByName(bottom.id);
+                                BI.extend(clone[bottom.id], {
+                                    top: r.top + insert.height
+                                });
+                            });
+                            var t = [];
+                            BI.each(bottoms, function (i, bottom) {
+                                var n = self.arrangement._getInDirectRelativeRegions(bottom.id, ["bottom"]).bottom;
+                                BI.each(n.top, function (i, region) {
+                                    if (!seen.contains(region.id)) {
+                                        seen.push(region.id);
+                                        var r = self.getRegionByName(region.id);
+                                        BI.extend(clone[region.id], {
+                                            height: r.height + insert.height
+                                        });
+                                    }
+                                });
+                                t = t.concat(n.bottom);
+                            });
+                            t = BI.uniq(t, function (i, region) {
+                                return region.id;
+                            });
+                            bottoms = t;
+                        }
+                        BI.each(bottomRegions, function (i, region) {
+                            if (!seen.contains(region.id)) {
+                                region.height = region.height + insert.height;
+                            }
+                        });
+                        this.arrangement.populate(BI.toArray(clone));
+                        this.arrangement.resize();
+                        flag = true;
+                    }
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+            this.position = null;
+        } else {
+            if (flag = this.arrangement.addRegion(region, position)) {
+                this._old = old;
+            }
+        }
+        return flag;
+    },
+
+    deleteRegion: function (name) {
+        var flag;
+        var old = this.getAllRegions();
+        if (flag = this.arrangement.deleteRegion(name)) {
+            this._old = old;
+        } else {
+            this._old = this.getAllRegions();
+            this.relayout();
+        }
+        return true;
+    },
+
+    setRegionSize: function (name, size) {
+        var flag;
+        var old = this.getAllRegions();
+        size = this._checkRegionSize(name, size);
+        if (flag = this.arrangement.setRegionSize(name, size)) {
+            this._old = old;
+        }
+        return flag;
+    },
+
+    setPosition: function (position, size) {
+        var self = this;
+        var at = this.arrangement.setPosition(position, size);
+        this.position = null;
+        if (!at) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    if (position.left < 0 || position.top < 0) {
+                        return null;
+                    }
+                    var offset = this.arrangement._getScrollOffset();
+                    position = {
+                        left: position.left + offset.left,
+                        top: position.top + offset.top
+                    };
+                    BI.some(this.getAllRegions(), function (id, region) {
+                        if (self.arrangement._isPositionInBounds(position, region)) {
+                            var at = self.arrangement._positionAt(position, region);
+                            if (at.type === "top-gap" || at.type === "bottom-gap") {
+                                self.arrangement._setArrangeSize({
+                                    top: region.top - 8 + (at.type === "bottom-gap" ? region.height : 0),
+                                    left: region.left,
+                                    width: region.width,
+                                    height: 16
+                                });
+                                self.position = {
+                                    insert: {
+                                        height: (size || {}).height
+                                    },
+                                    type: at.type,
+                                    region: region
+                                };
+                                self.arrangement._start();
+                            }
+                            return true;
+                        }
+                    });
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        return this.position || at;
+    },
+
+    setRegionPosition: function (name, position) {
+        var region = this.getRegionByName(name);
+        region.el.element.css("zIndex", ++this.zIndex);
+        return this.arrangement.setRegionPosition(name, position);
+    },
+
+    zoom: function (ratio) {
+        this.arrangement.zoom(ratio);
+    },
+
+    resize: function () {
+        this.arrangement.resize();
+    },
+
+    relayout: function () {
+        return this.arrangement.relayout();
+    },
+
+    setLayoutType: function (type) {
+        var self = this;
+        this._setLayoutType(type);
+        this.arrangement.setLayoutType(type);
+    },
+
+    getLayoutType: function () {
+        return this.arrangement.getLayoutType();
+    },
+
+    getLayoutRatio: function () {
+        return this.arrangement.getLayoutRatio();
+    },
+
+    getHelper: function () {
+        return this.arrangement.getHelper();
+    },
+
+    getRegionByName: function (name) {
+        return this.arrangement.getRegionByName(name);
+    },
+
+    getAllRegions: function () {
+        return this.arrangement.getAllRegions();
+    },
+
+    revoke: function () {
+        if (this._old) {
+            this.populate(BI.toArray(this._old));
+        }
+    },
+
+    populate: function (items) {
+        var self = this;
+        BI.each(items, function (i, item) {
+            self._initResizable(item.el);
+        });
+        this.arrangement.populate(items);
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                BI.nextTick(function () {
+                    self.arrangement.resize();
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+    }
+});
+BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE";
+BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_RESIZE";
+BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE";
+BI.AdaptiveArrangement.EVENT_RESIZE = "AdaptiveArrangement.EVENT_RESIZE";
+$.shortcut('bi.adaptive_arrangement', BI.AdaptiveArrangement);/**
+ * Arrangement的block面板
+ *
+ * Created by GUY on 2016/3/1.
+ * @class BI.ArrangementBlock
+ * @extends BI.Widget
+ */
+BI.ArrangementBlock = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ArrangementBlock.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement-block"
+        });
+    },
+
+    _init: function () {
+        BI.ArrangementBlock.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        
+    }
+});
+$.shortcut('bi.arrangement_block', BI.ArrangementBlock);/**
+ * Arrangement的drop面板
+ *
+ * Created by GUY on 2016/3/1.
+ * @class BI.ArrangementDroppable
+ * @extends BI.Widget
+ */
+BI.ArrangementDroppable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ArrangementDroppable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement-droppable"
+        });
+    },
+
+    _init: function () {
+        BI.ArrangementDroppable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        
+    }
+});
+$.shortcut('bi.arrangement_droppable', BI.ArrangementDroppable);/**
+ * 布局
+ *
+ * Created by GUY on 2016/2/23.
+ * @class BI.Arrangement
+ * @extends BI.Widget
+ */
+BI.Arrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Arrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement",
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            isNeedReLayout: true,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.Arrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.arrangement_droppable",
+            cls: "arrangement-block",
+            invisible: true
+        });
+        this.block = BI.createWidget({
+            type: "bi.arrangement_block",
+            invisible: true
+        });
+        this.droppable = BI.createWidget({
+            type: "bi.layout",
+            cls: "arrangement-drop-container",
+            invisible: true
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            items: o.items.concat([this.block, this.arrangement, {
+                el: this.droppable,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }])
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: "100%",
+            height: "100%",
+            scrollable: true,
+            items: [this.container]
+        });
+
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: this,
+            items: [this.scrollContainer]
+        });
+        this.regions = {};
+        this.locations = {};
+        this.drops = {};
+        this.storeDrops = {};
+        if (o.items.length > 0) {
+            BI.nextTick(function () {
+                self.populate(o.items);
+            });
+        }
+    },
+
+    ////初始化操作////
+    _calculateRegions: function (items) {
+        var self = this, o = this.options;
+        this.regions = {};
+        this.drops = {};
+        BI.each(items, function (i, item) {
+            var region = self._createOneRegion(item);
+            self.regions[region.id] = region;
+            var drop = self._createOneDrop(region);
+            self.drops[drop.id] = drop;
+            self.storeDrops[drop.id] = drop;
+        });
+    },
+
+    //定方位
+    _locationRegion: function () {
+        var self = this, o = this.options;
+        this.locations = {};
+        var reg = [];
+        BI.each(this.regions, function (id, region) {
+            var t = new BI.Region(region.left, region.top, region.width, region.height);
+            t.id = id;
+            reg.push(t);
+            self.locations[id] = {top: [], left: [], right: [], bottom: []};
+        });
+        BI.each(reg, function (i, dim) {
+            var topRegion = new BI.Region(dim.x, 0, dim.w, dim.y),
+                bottomRegion = new BI.Region(dim.x, dim.y + dim.h, dim.w, BI.MAX),
+                leftRegion = new BI.Region(0, dim.y, dim.x, dim.h),
+                rightRegion = new BI.Region(dim.x + dim.w, dim.y, BI.MAX, dim.h);
+            BI.each(reg, function (j, tar) {
+                if (i !== j) {
+                    if (tar.isIntersects(topRegion) && self._isLessThanEqual(tar.y + tar.h, dim.y)) {
+                        self.locations[dim.id].top.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(bottomRegion) && self._isMoreThanEqual(tar.y, dim.y + dim.h)) {
+                        self.locations[dim.id].bottom.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(leftRegion) && self._isLessThanEqual(tar.x + tar.w, dim.x)) {
+                        self.locations[dim.id].left.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(rightRegion) && self._isMoreThanEqual(tar.x, dim.x + dim.w)) {
+                        self.locations[dim.id].right.push(self.regions[tar.id]);
+                    }
+                }
+            });
+        });
+    },
+
+    _isEqual: function (num1, num2) {
+        return Math.abs(num1 - num2) < 2;
+    },
+
+    _isLessThan: function (num1, num2) {
+        return num1 < num2 && !this._isEqual(num1, num2);
+    },
+
+    _isMoreThan: function (num1, num2) {
+        return num1 > num2 && !this._isEqual(num1, num2);
+    },
+
+    _isLessThanEqual: function (num1, num2) {
+        return num1 <= num2 || this._isEqual(num1, num2);
+    },
+
+    _isMoreThanEqual: function (num1, num2) {
+        return num1 >= num2 || this._isEqual(num1, num2);
+    },
+
+    ////方法////
+    _isPositionInBounds: function (position, bound) {
+        var region = new BI.Region(bound.left, bound.top, bound.width, bound.height);
+        return region.isPointInside(position.left, position.top);
+    },
+
+    //获取某区域等量相关联的区域
+    _getEquivalentRelativeRegions: function (name, direction) {
+        var self = this;
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var result = [];
+        var target = this.regions[name];
+        var tops = this.locations[name].top;
+        var bottoms = this.locations[name].bottom;
+        var lefts = this.locations[name].left;
+        var rights = this.locations[name].right;
+        var finded = direction.contains("top") && BI.some(tops, function (i, region) {
+                if (self._isEqual(region.top + region.height, target.top) && self._isEqual(region.left, target.left) && self._isEqual(region.width, target.width)) {
+                    var clone = BI.clone(region);
+                    clone.height = region.height + target.height;
+                    result.push(clone);
+                    return true;
+                }
+            });
+        if (!finded) {
+            finded = direction.contains("bottom") && BI.some(bottoms, function (i, region) {
+                    if (self._isEqual(target.top + target.height, region.top) && self._isEqual(region.left, target.left) && self._isEqual(region.width, target.width)) {
+                        var clone = BI.clone(region);
+                        clone.top = region.top - target.height;
+                        clone.height = region.height + target.height;
+                        result.push(clone);
+                        return true;
+                    }
+                });
+            if (!finded) {
+                finded = direction.contains("left") && BI.some(lefts, function (i, region) {
+                        if (self._isEqual(region.left + region.width, target.left) && self._isEqual(region.top, target.top) && self._isEqual(region.height, target.height)) {
+                            var clone = BI.clone(region);
+                            clone.width = region.width + target.width;
+                            result.push(clone);
+                            return true;
+                        }
+                    });
+                if (!finded) {
+                    finded = direction.contains("right") && BI.some(rights, function (i, region) {
+                            if (self._isEqual(target.left + target.width, region.left) && self._isEqual(region.top, target.top) && self._isEqual(region.height, target.height)) {
+                                var clone = BI.clone(region);
+                                clone.left = region.left - target.width;
+                                clone.width = region.width + target.width;
+                                result.push(clone);
+                                return true;
+                            }
+                        });
+                    if (!finded) {
+                        var findTopRegions = [], findBottomRegions = [];
+                        direction.contains("top") && BI.each(tops, function (i, region) {
+                            if (self._isEqual(region.top + region.height, target.top)
+                                && self._isMoreThanEqual(region.left, target.left)
+                                && self._isLessThanEqual(region.left + region.width, target.left + target.width)) {
+                                findTopRegions.push(region);
+                            }
+                        });
+                        direction.contains("bottom") && BI.each(bottoms, function (i, region) {
+                            if (self._isEqual(target.top + target.height, region.top)
+                                && self._isMoreThanEqual(region.left, target.left)
+                                && self._isLessThanEqual(region.left + region.width, target.left + target.width)) {
+                                findBottomRegions.push(region);
+                            }
+                        });
+                        var topValid = isRegionsValid(findTopRegions, "top"), bottomValid = isRegionsValid(findBottomRegions, "bottom");
+                        if (topValid && bottomValid) {
+                            BI.each(findTopRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.height = region.height + target.height / 2;
+                                result.push(clone);
+                            });
+                            BI.each(findBottomRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.top = region.top - target.height / 2;
+                                clone.height = region.height + target.height / 2;
+                                result.push(clone);
+                            });
+                        } else if (topValid) {
+                            BI.each(findTopRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.height = region.height + target.height;
+                                result.push(clone);
+                            });
+                        } else if (bottomValid) {
+                            BI.each(findBottomRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.top = region.top - target.height;
+                                clone.height = region.height + target.height;
+                                result.push(clone);
+                            });
+                        }
+                        if (!topValid && !bottomValid) {
+                            var findLeftRegions = [], findRightRegions = [];
+                            direction.contains("left") && BI.each(lefts, function (i, region) {
+                                if (self._isEqual(region.left + region.width, target.left)
+                                    && self._isMoreThanEqual(region.top, target.top)
+                                    && self._isLessThanEqual(region.top + region.height, target.top + target.height)) {
+                                    findLeftRegions.push(region);
+                                }
+                            });
+                            direction.contains("right") && BI.each(rights, function (i, region) {
+                                if (self._isEqual(target.left + target.width, region.left)
+                                    && self._isMoreThanEqual(region.top, target.top)
+                                    && self._isLessThanEqual(region.top + region.height, target.top + target.height)) {
+                                    findRightRegions.push(region);
+                                }
+                            });
+                            var leftValid = isRegionsValid(findLeftRegions, "left"), rightValid = isRegionsValid(findRightRegions, "right");
+                            if (leftValid && rightValid) {
+                                BI.each(findLeftRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.width = region.width + target.width / 2;
+                                    result.push(clone);
+                                });
+                                BI.each(findRightRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.left = region.left - target.width / 2;
+                                    clone.width = region.width + target.width / 2;
+                                    result.push(clone);
+                                });
+                            } else if (leftValid) {
+                                BI.each(findLeftRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.width = region.width + target.width;
+                                    result.push(clone);
+                                });
+                            } else if (rightValid) {
+                                BI.each(findRightRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.left = region.left - target.width;
+                                    clone.width = region.width + target.width;
+                                    result.push(clone);
+                                });
+                            }
+
+                            //上下左右都不可行
+                            if (!leftValid && !rightValid) {
+
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+        function isRegionsValid(regions, dir) {
+            var occupied = self._getRegionOccupied(regions);
+            switch (dir) {
+                case "top":
+                case "bottom":
+                    return self._isEqual(occupied.left, target.left) && self._isEqual(occupied.width, target.width);
+                case "left":
+                case "right":
+                    return self._isEqual(occupied.top, target.top) && self._isEqual(occupied.height, target.height);
+            }
+            return false;
+        }
+    },
+
+    //获取某区域直接相关联的区域
+    _getDirectRelativeRegions: function (name, direction) {
+        var self = this;
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var result = [];
+        var target = this.regions[name];
+        var tops = this.locations[name].top;
+        var bottoms = this.locations[name].bottom;
+        var lefts = this.locations[name].left;
+        var rights = this.locations[name].right;
+        var finded = direction.contains("top") && BI.some(tops, function (i, region) {
+                if (self._isEqual(region.top + region.height, target.top)
+                    && ((self._isMoreThanEqual(region.left, target.left) && self._isLessThan(region.left, target.left + target.width))
+                    || (self._isMoreThan(region.left + region.width, target.left) && self._isLessThanEqual(region.left + region.width, target.left + target.width))
+                    || (self._isLessThan(region.left, target.left) && self._isMoreThan(region.left + region.width, target.left + target.width)))) {
+                    var clone = BI.clone(region);
+                    clone.height = region.height + target.height;
+                    result.push(clone);
+                }
+            });
+        if (!finded) {
+            finded = direction.contains("bottom") && BI.some(bottoms, function (i, region) {
+                    if (self._isEqual(target.top + target.height, region.top)
+                        && ((self._isMoreThanEqual(region.left, target.left) && self._isLessThan(region.left, target.left + target.width))
+                        || (self._isMoreThan(region.left + region.width, target.left) && self._isLessThanEqual(region.left + region.width, target.left + target.width))
+                        || (self._isLessThan(region.left, target.left) && self._isMoreThan(region.left + region.width, target.left + target.width)))) {
+                        var clone = BI.clone(region);
+                        clone.top = region.top - target.height;
+                        clone.height = region.height + target.height;
+                        result.push(clone);
+                    }
+                });
+            if (!finded) {
+                finded = direction.contains("left") && BI.some(lefts, function (i, region) {
+                        if (self._isEqual(region.left + region.width, target.left)
+                            && ((self._isMoreThanEqual(region.top, target.top) && self._isLessThan(region.top, target.top + target.height))
+                            || (self._isMoreThan(region.top + region.height, target.top) && self._isLessThanEqual(region.top + region.height, target.top + target.height))
+                            || (self._isLessThan(region.top, target.top) && self._isMoreThan(region.top + region.height, target.top + target.height)))) {
+                            var clone = BI.clone(region);
+                            clone.width = region.width + target.width;
+                            result.push(clone);
+                        }
+                    });
+                if (!finded) {
+                    finded = direction.contains("right") && BI.some(rights, function (i, region) {
+                            if (self._isEqual(target.left + target.width, region.left)
+                                && ((self._isMoreThanEqual(region.top, target.top) && self._isLessThan(region.top, target.top + target.height))
+                                || (self._isMoreThan(region.top + region.height, target.top) && self._isLessThanEqual(region.top + region.height, target.top + target.height))
+                                || (self._isLessThan(region.top, target.top) && self._isMoreThan(region.top + region.height, target.top + target.height)))) {
+                                var clone = BI.clone(region);
+                                clone.left = region.left - target.width;
+                                clone.width = region.width + target.width;
+                                result.push(clone);
+                            }
+                        });
+                }
+            }
+        }
+        return result;
+    },
+
+    //获取间接相关联的区域,即调整name区域后需要附带调整的所有相关区域(包括自身)
+    _getInDirectRelativeRegions: function (name, direction) {
+        var self = this, dict = ["top", "left", "right", "bottom"];
+        var result = {};
+        direction || (direction = dict);
+        function recursion(regions, dir, store, cache) {
+            BI.each(regions, function (i, region) {
+                if (cache[region.id]) {
+                    return;
+                }
+                cache[region.id] = true;
+                if (!store[dict[3 - dir]]) {
+                    store[dict[3 - dir]] = [];
+                }
+                store[dict[3 - dir]].push(region);
+                recursion(self._getDirectRelativeRegions(region.id, [dict[dir]]), 3 - dir, store, cache);
+            })
+        }
+
+        if (direction.contains("top")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("top"), store, cache);
+            store["top"] = BI.sortBy(store["top"], "left");
+            store["bottom"] = BI.sortBy(store["bottom"], "left");
+            result["top"] = store;
+        }
+        if (direction.contains("bottom")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("bottom"), store, cache);
+            store["top"] = BI.sortBy(store["top"], "left");
+            store["bottom"] = BI.sortBy(store["bottom"], "left");
+            result["bottom"] = store;
+        }
+        if (direction.contains("left")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("left"), store, cache);
+            store["left"] = BI.sortBy(store["left"], "top");
+            store["right"] = BI.sortBy(store["right"], "top");
+            result["left"] = store;
+        }
+        if (direction.contains("right")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("right"), store, cache);
+            store["left"] = BI.sortBy(store["left"], "top");
+            store["right"] = BI.sortBy(store["right"], "top");
+            result["right"] = store;
+        }
+        return result;
+    },
+
+    _getLeftAlignRegions: function (name) {
+        var self = this;
+        var tops = this._getDirectRelativeRegions(name, ["top"]);
+        var bottoms = this._getDirectRelativeRegions(name, ["bottom"]);
+        var current = this.regions[name];
+        var rtop = [], rbottom = [];
+        BI.each(tops, function (i, region) {
+            if (self._isEqual(region.left, current.left)) {
+                rtop.push(region);
+            }
+        });
+        BI.each(bottoms, function (i, region) {
+            if (self._isEqual(region.left, current.left)) {
+                rbottom.push(region);
+            }
+        });
+        return {
+            top: rtop,
+            bottom: rbottom
+        }
+    },
+
+    _getRightAlignRegions: function (name) {
+        var self = this;
+        var tops = this._getDirectRelativeRegions(name, ["top"]);
+        var bottoms = this._getDirectRelativeRegions(name, ["bottom"]);
+        var current = this.regions[name];
+        var rtop = [], rbottom = [];
+        BI.each(tops, function (i, region) {
+            if (self._isEqual(region.left + region.width, current.left + current.width)) {
+                rtop.push(region);
+            }
+        });
+        BI.each(bottoms, function (i, region) {
+            if (self._isEqual(region.left + region.width, current.left + current.width)) {
+                rbottom.push(region);
+            }
+        });
+        return {
+            top: rtop,
+            bottom: rbottom
+        }
+    },
+
+    _getTopAlignRegions: function (name) {
+        var self = this;
+        var lefts = this._getDirectRelativeRegions(name, ["left"]);
+        var rights = this._getDirectRelativeRegions(name, ["right"]);
+        var current = this.regions[name];
+        var rleft = [], rright = [];
+        BI.each(lefts, function (i, region) {
+            if (self._isEqual(region.top, current.top)) {
+                rleft.push(region);
+            }
+        });
+        BI.each(rights, function (i, region) {
+            if (self._isEqual(region.top, current.top)) {
+                rright.push(region);
+            }
+        });
+        return {
+            left: rleft,
+            right: rright
+        }
+    },
+
+    _getBottomAlignRegions: function (name) {
+        var self = this;
+        var lefts = this._getDirectRelativeRegions(name, ["left"]);
+        var rights = this._getDirectRelativeRegions(name, ["right"]);
+        var current = this.regions[name];
+        var rleft = [], rright = [];
+        BI.each(lefts, function (i, region) {
+            if (self._isEqual(region.top + region.height, current.top + current.height)) {
+                rleft.push(region);
+            }
+        });
+        BI.each(rights, function (i, region) {
+            if (self._isEqual(region.top + region.height, current.top + current.height)) {
+                rright.push(region);
+            }
+        });
+        return {
+            left: rleft,
+            right: rright
+        }
+    },
+
+    //获取占有的最大Region
+    _getRegionOccupied: function (regions) {
+        var self = this, o = this.options;
+        if (BI.size(regions || this.regions) <= 0) {
+            return {
+                left: 0,
+                top: 0,
+                width: 0,
+                height: 0
+            }
+        }
+        var minLeft = BI.MAX, maxLeft = BI.MIN, minTop = BI.MAX, maxTop = BI.MIN;
+        BI.each(regions || this.regions, function (id, region) {
+            minLeft = Math.min(minLeft, region.left);
+            maxLeft = Math.max(maxLeft, region.left + region.width);
+            minTop = Math.min(minTop, region.top);
+            maxTop = Math.max(maxTop, region.top + region.height);
+        });
+        return {
+            left: minLeft,
+            top: minTop,
+            width: maxLeft - minLeft,
+            height: maxTop - minTop
+        }
+    },
+
+    //两个区域的交叉面积
+    _getCrossArea: function (region1, region2) {
+        if (region1.left <= region2.left) {
+            if (region1.top <= region2.top) {
+                if (region1.top + region1.height > region2.top && region1.left + region1.width > region2.left) {
+                    if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region1.left + region1.width, region2.left)) {
+                        return 0;
+                    }
+                    return (region1.top + region1.height - region2.top) * (region1.left + region1.width - region2.left);
+                }
+            } else {
+                if (region2.top + region2.height > region1.top && region1.left + region1.width > region2.left) {
+                    if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region1.left + region1.width, region2.left)) {
+                        return 0;
+                    }
+                    return (region2.top + region2.height - region1.top) * (region1.left + region1.width - region2.left);
+                }
+            }
+        } else {
+            if (region1.top <= region2.top) {
+                if (region1.top + region1.height > region2.top && region2.left + region2.width > region1.left) {
+                    if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region2.left + region2.width, region1.left)) {
+                        return 0;
+                    }
+                    return (region1.top + region1.height - region2.top) * (region2.left + region2.width - region1.left);
+                }
+            } else {
+                if (region2.top + region2.height > region1.top && region2.left + region2.width > region1.left) {
+                    if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region2.left + region2.width, region1.left)) {
+                        return 0;
+                    }
+                    return (region2.top + region2.height - region1.top) * (region2.left + region2.width - region1.left);
+                }
+            }
+        }
+        return 0;
+    },
+
+    //是否有覆盖的组件
+    _isRegionOverlay: function (regions) {
+        var reg = [];
+        BI.each(regions || this.regions, function (id, region) {
+            reg.push(new BI.Region(region.left, region.top, region.width, region.height));
+        });
+        for (var i = 0, len = reg.length; i < len; i++) {
+            for (var j = i + 1; j < len; j++) {
+                var area1 = {
+                    left: reg[i].x,
+                    top: reg[i].y,
+                    width: reg[i].w,
+                    height: reg[i].h
+                };
+                var area2 = {
+                    left: reg[j].x,
+                    top: reg[j].y,
+                    width: reg[j].w,
+                    height: reg[j].h
+                };
+                if (reg[i].isIntersects(reg[j]) && this._getCrossArea(area1, area2) > 1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    },
+
+    //布局是否是优良的
+    _isArrangeFine: function (regions) {
+        switch (this.options.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isRegionOverlay()) {
+                    return false;
+                }
+                var maxRegion = this._getRegionOccupied(regions);
+                var area = maxRegion.width * maxRegion.height;
+                var all = 0;
+                BI.each(regions || this.regions, function (id, region) {
+                    all += region.width * region.height;
+                });
+                return Math.abs(area - all) < 8;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (this._isRegionOverlay()) {
+                    return false;
+                }
+        }
+        return true;
+    },
+
+    _getRegionNames: function (regions) {
+        var names = [];
+        BI.each(regions || this.regions, function (i, region) {
+            names.push(region.id || region.attr("id"));
+        });
+        return names;
+    },
+
+    _getRegionsByNames: function (names, regions) {
+        names = BI.isArray(names) ? names : [names];
+        regions = regions || this.regions;
+        if (BI.isArray(regions)) {
+            var result = [];
+            BI.each(regions, function (i, region) {
+                if (names.contains(region.id || region.attr("id"))) {
+                    result.push(region);
+                }
+            });
+        } else {
+            var result = {};
+            BI.each(names, function (i, name) {
+                result[name] = regions[name];
+            });
+        }
+        return result;
+    },
+
+    _cloneRegion: function (regions) {
+        var clone = {};
+        BI.each(regions || this.regions, function (id, region) {
+            clone[id] = {};
+            clone[id].el = region.el;
+            clone[id].id = region.id;
+            clone[id].left = region.left;
+            clone[id].top = region.top;
+            clone[id].width = region.width;
+            clone[id].height = region.height;
+        });
+        return clone;
+    },
+
+    //测试合法性
+    _test: function (regions) {
+        var self = this;
+        return !BI.any(regions || this.regions, function (i, region) {
+            if (BI.isNaN(region.width) || BI.isNaN(region.height) || region.width <= 21 || region.height <= 21) {
+                return true;
+            }
+        })
+    },
+
+    //对区域进行划分
+    _splitRegions: function (name) {
+        var result = [];
+        var tid = BI.UUID();
+        var _left = this._getLeftAlignRegions(name);
+        var _right = this._getRightAlignRegions(name);
+        var _top = this._getTopAlignRegions(name);
+        var _bottom = this._getBottomAlignRegions(name);
+        if (_left.top.length > 0) {
+            var upid = _left.top[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[upid].width) / 2;//两个组件中较小宽度的一半
+            var left = (clone[name].left + clone[upid].left) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: left,
+                top: clone[upid].top,
+                width: split,
+                height: clone[name].height + clone[upid].height
+            };
+            BI.extend(clone[name], {
+                left: left + split,
+                width: clone[name].width - split - (left - clone[name].left)
+            });
+            BI.extend(clone[upid], {
+                left: left + split,
+                width: clone[upid].width - split - (left - clone[upid].left)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "left-top",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_left.bottom.length > 0) {
+            var bottomid = _left.bottom[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[bottomid].width) / 2;
+            var left = (clone[name].left + clone[bottomid].left) / 2;
+            var insert = clone[tid] = {//新增的区域
+                left: left,
+                top: clone[name].top,
+                width: split,
+                height: clone[name].height + clone[bottomid].height
+            };
+            BI.extend(clone[name], {
+                left: left + split,
+                width: clone[name].width - split - (left - clone[name].left)
+            });
+            BI.extend(clone[bottomid], {
+                left: left + split,
+                width: clone[bottomid].width - split - (left - clone[bottomid].left)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-left",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_right.top.length > 0) {
+            var upid = _right.top[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[upid].width) / 2;//两个组件中较小宽度的一半
+            var right = (clone[name].left + clone[name].width + clone[upid].left + clone[upid].width) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: right - split,
+                top: clone[upid].top,
+                width: split,
+                height: clone[name].height + clone[upid].height
+            };
+            BI.extend(clone[name], {
+                width: right - clone[name].left - split
+            });
+            BI.extend(clone[upid], {
+                width: right - clone[upid].left - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-right",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_right.bottom.length > 0) {
+            var bottomid = _right.bottom[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[bottomid].width) / 2;//两个组件中较小宽度的一半
+            var right = (clone[name].left + clone[name].width + clone[bottomid].left + clone[bottomid].width) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: right - split,
+                top: clone[name].top,
+                width: split,
+                height: clone[name].height + clone[bottomid].height
+            };
+            BI.extend(clone[name], {
+                width: right - clone[name].left - split
+            });
+            BI.extend(clone[bottomid], {
+                width: right - clone[bottomid].left - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-right",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_top.left.length > 0) {
+            var leftid = _top.left[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[leftid].height) / 2;//两个组件中较小高度的一半
+            var top = (clone[name].top + clone[leftid].top) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                top: top,
+                left: clone[leftid].left,
+                height: split,
+                width: clone[name].width + clone[leftid].width
+            };
+            BI.extend(clone[name], {
+                top: top + split,
+                height: clone[name].height - split - (top - clone[name].top)
+            });
+            BI.extend(clone[leftid], {
+                top: top + split,
+                height: clone[leftid].height - split - (top - clone[leftid].top)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-left",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_top.right.length > 0) {
+            var rightid = _top.right[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[rightid].height) / 2;//两个组件中较小高度的一半
+            var top = (clone[name].top + clone[rightid].top) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                top: top,
+                left: clone[name].left,
+                height: split,
+                width: clone[name].width + clone[rightid].width
+            };
+            BI.extend(clone[name], {
+                top: top + split,
+                height: clone[name].height - split - (top - clone[name].top)
+            });
+            BI.extend(clone[rightid], {
+                top: top + split,
+                height: clone[rightid].height - split - (top - clone[rightid].top)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-right-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_bottom.left.length > 0) {
+            var leftid = _bottom.left[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[leftid].height) / 2;//两个组件中较小高度的一半
+            var bottom = (clone[name].top + clone[name].height + clone[leftid].top + clone[leftid].height) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: clone[leftid].left,
+                top: bottom - split,
+                height: split,
+                width: clone[name].width + clone[leftid].width
+            };
+            BI.extend(clone[name], {
+                height: bottom - clone[name].top - split
+            });
+            BI.extend(clone[leftid], {
+                height: bottom - clone[leftid].top - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-left-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_bottom.right.length > 0) {
+            var rightid = _bottom.right[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[rightid].height) / 2;//两个组件中较小高度的一半
+            var bottom = (clone[name].top + clone[name].height + clone[rightid].top + clone[rightid].height) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: clone[name].left,
+                top: bottom - split,
+                height: split,
+                width: clone[name].width + clone[rightid].width
+            };
+            BI.extend(clone[name], {
+                height: bottom - clone[name].top - split
+            });
+            BI.extend(clone[rightid], {
+                height: bottom - clone[rightid].top - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-right-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        //有上方居中drop
+        var lefts = _top.left, rights = _top.right;
+        if (lefts.length > 0 && rights.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (lefts.length > 0 || rights.length > 0) {
+                var clone = this._cloneRegion();
+                if (lefts.length > 0) {
+                    store.push(this.regions[lefts[0].id]);
+                }
+                if (rights.length > 0) {
+                    store.push(this.regions[rights[0].id]);
+                }
+                count++;
+                var top = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.top;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.height;
+                    }).height / 2;
+                var insert = clone[tid] = {
+                    left: occupied.left,
+                    width: occupied.width,
+                    top: top,
+                    height: split
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        top: top + split,
+                        height: region.height - split - (top - region.top)
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "top-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (lefts.length > 0) lefts = this._getTopAlignRegions(lefts[0].id).left;
+                if (rights.length > 0) rights = this._getTopAlignRegions(rights[0].id).right;
+            }
+        }
+        //有下方居中drop
+        var lefts = _bottom.left, rights = _bottom.right;
+        if (lefts.length > 0 && rights.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (lefts.length > 0 || rights.length > 0) {
+                var clone = this._cloneRegion();
+                if (lefts.length > 0) {
+                    store.push(this.regions[lefts[0].id]);
+                }
+                if (rights.length > 0) {
+                    store.push(this.regions[rights[0].id]);
+                }
+                count++;
+                var bottom = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.top + r.height;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.height;
+                    }).height / 2;
+                var insert = clone[tid] = {
+                    left: occupied.left,
+                    width: occupied.width,
+                    top: bottom - split,
+                    height: split
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        height: bottom - region.top - split
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "bottom-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (lefts.length > 0) lefts = this._getBottomAlignRegions(lefts[0].id).left;
+                if (rights.length > 0) rights = this._getBottomAlignRegions(rights[0].id).right;
+            }
+        }
+        //有左方居中drop
+        var tops = _left.top, bottoms = _left.bottom;
+        if (tops.length > 0 && bottoms.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (tops.length > 0 || bottoms.length > 0) {
+                var clone = this._cloneRegion();
+                if (tops.length > 0) {
+                    store.push(this.regions[tops[0].id]);
+                }
+                if (bottoms.length > 0) {
+                    store.push(this.regions[bottoms[0].id]);
+                }
+                count++;
+                var left = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.left;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.width;
+                    }).width / 2;
+                var insert = clone[tid] = {
+                    left: left,
+                    width: split,
+                    top: occupied.top,
+                    height: occupied.height
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        left: left + split,
+                        width: region.width - split - (left - region.left)
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "left-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (tops.length > 0) tops = this._getLeftAlignRegions(tops[0].id).top;
+                if (bottoms.length > 0) bottoms = this._getLeftAlignRegions(bottoms[0].id).bottom;
+            }
+        }
+        //有右方居中drop
+        var tops = _right.top, bottoms = _right.bottom;
+        if (tops.length > 0 && bottoms.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (tops.length > 0 || bottoms.length > 0) {
+                var clone = this._cloneRegion();
+                if (tops.length > 0) {
+                    store.push(this.regions[tops[0].id]);
+                }
+                if (bottoms.length > 0) {
+                    store.push(this.regions[bottoms[0].id]);
+                }
+                count++;
+                var right = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.left + r.width;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.width;
+                    }).width / 2;
+                var insert = clone[tid] = {
+                    left: right - split,
+                    width: split,
+                    top: occupied.top,
+                    height: occupied.height
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        width: right - region.left - split
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "right-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (tops.length > 0) tops = this._getRightAlignRegions(tops[0].id).top;
+                if (bottoms.length > 0) bottoms = this._getRightAlignRegions(bottoms[0].id).bottom;
+            }
+        }
+        var lefts = this._getEquivalentRelativeRegions(name, ["left"]);
+        if (lefts.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var left = this.regions[lefts[0].id];
+            var width = left.width;
+            var all = left.width + _cur.width;
+            var ratio = width / all;
+            var split = all / 3;
+            var lleft = width - split * ratio, rleft = _cur.width - split * (1 - ratio);
+            var insert = false;
+            if (lleft <= 21) {
+                rleft = _cur.width - split;
+                if (rleft <= 21) {
+
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left,
+                        width: split,
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left + split,
+                        width: _cur.width - split
+                    });
+                }
+            } else if (rleft <= 21) {
+                lleft = width - split;
+                if (lleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left - split,
+                        width: split,
+                    };
+                    BI.extend(clone[left.id], {
+                        top: left.top,
+                        height: left.height,
+                        left: left.left,
+                        width: left.width - split
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: left.left + lleft,
+                    width: split,
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left + _cur.width - rleft,
+                    width: rleft
+                });
+                BI.extend(clone[left.id], {
+                    top: left.top,
+                    height: left.height,
+                    left: left.left,
+                    width: lleft
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "left-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var rights = this._getEquivalentRelativeRegions(name, ["right"]);
+        if (rights.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var right = this.regions[rights[0].id];
+            var width = right.width;
+            var all = right.width + _cur.width;
+            var ratio = width / all;
+            var split = all / 3;
+            var lleft = _cur.width - split * (1 - ratio), rleft = width - split * ratio;
+            var insert = false;
+            if (lleft <= 21) {
+                rleft = width - split;
+                if (rleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: right.top,
+                        height: right.height,
+                        left: right.left,
+                        width: split
+                    };
+                    BI.extend(clone[right.id], {
+                        top: right.top,
+                        height: right.height,
+                        left: right.left + split,
+                        width: right.width - split
+                    })
+                }
+            } else if (rleft <= 21) {
+                lleft = _cur.width - split;
+                if (lleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left + lleft,
+                        width: split
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left,
+                        width: _cur.width - split
+                    })
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left + lleft,
+                    width: split
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left,
+                    width: lleft
+                });
+                BI.extend(clone[right.id], {
+                    top: right.top,
+                    height: right.height,
+                    left: right.left + right.width - rleft,
+                    width: rleft
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "right-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var tops = this._getEquivalentRelativeRegions(name, ["top"]);
+        if (tops.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var top = this.regions[tops[0].id];
+            var height = top.height;
+            var all = top.height + _cur.height;
+            var ratio = height / all;
+            var split = all / 3;
+            var tleft = height - split * ratio, bleft = _cur.height - split * (1 - ratio);
+            var insert = false;
+            if (tleft <= 21) {
+                bleft = _cur.height - split;
+                if (bleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        width: _cur.width,
+                        left: _cur.left,
+                        height: split
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top + split,
+                        height: _cur.height - split,
+                        left: _cur.left,
+                        width: _cur.width
+                    });
+                }
+            }
+            if (bleft <= 21) {
+                tleft = height - split;
+                if (tleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top - split,
+                        height: split,
+                        left: _cur.left,
+                        width: _cur.width
+                    };
+                    BI.extend(clone[top.id], {
+                        top: top.top,
+                        height: top.height - split,
+                        left: top.left,
+                        width: top.width
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: top.top + tleft,
+                    height: split,
+                    left: _cur.left,
+                    width: _cur.width
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top + _cur.height - bleft,
+                    height: bleft,
+                    left: _cur.left,
+                    width: _cur.width
+                });
+                BI.extend(clone[top.id], {
+                    top: top.top,
+                    height: tleft,
+                    left: top.left,
+                    width: top.width
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "top-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var bottoms = this._getEquivalentRelativeRegions(name, ["bottom"]);
+        if (bottoms.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var bottom = this.regions[bottoms[0].id];
+            var height = bottom.height;
+            var all = bottom.height + _cur.height;
+            var ratio = height / all;
+            var split = all / 3;
+            var tleft = _cur.height - split * (1 - ratio), bleft = height - split * ratio;
+            var insert = false;
+            if (tleft <= 21) {
+                bleft = height - split;
+                if (bleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: bottom.top,
+                        height: bottom.height,
+                        left: bottom.left,
+                        width: split
+                    };
+                    BI.extend(clone[bottom.id], {
+                        top: bottom.top + split,
+                        height: bottom.height - split,
+                        left: bottom.left,
+                        width: bottom.width
+                    });
+                }
+            } else if (bleft <= 21) {
+                tleft = _cur.height - split;
+                if (tleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top + tleft,
+                        height: split,
+                        left: _cur.left,
+                        width: _cur.width
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height - split,
+                        left: _cur.left,
+                        width: _cur.width
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top + tleft,
+                    height: split,
+                    left: _cur.left,
+                    width: _cur.width,
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: tleft,
+                    left: _cur.left,
+                    width: _cur.width
+                });
+                BI.extend(clone[bottom.id], {
+                    top: bottom.top + bottom.height - bleft,
+                    height: bleft,
+                    left: bottom.left,
+                    width: bottom.width
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "bottom-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        if (tops.length >= 1) {
+            result.push({
+                type: "top-gap"
+            });
+        }
+        if (bottoms.length >= 1) {
+            result.push({
+                type: "bottom-gap"
+            });
+        }
+        //上
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2,
+        };
+        BI.extend(clone[name], {
+            top: _cur.top + _cur.height / 2,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "top",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //下
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top + _cur.height / 2,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "bottom",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //左
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width / 2,
+            height: _cur.height
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left + _cur.width / 2,
+            width: _cur.width / 2,
+            height: _cur.height
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "left",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //右
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left + _cur.width / 2,
+            width: _cur.width / 2,
+            height: _cur.height
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width / 2,
+            height: _cur.height
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "right",
+                regions: clone,
+                insert: insert
+            })
+        }
+        return result;
+    },
+
+    _positionAt: function (position, bound) {
+        var left = position.left - bound.left, top = position.top - bound.top;
+        var right = bound.width - left, bottom = bound.height - top;
+        var halfW = bound.width / 2, halfH = bound.height / 2;
+        if (left < 0 || top < 0 || right < 0 || bottom < 0) {
+            return;
+        }
+        var devides = this._splitRegions(bound.id);
+        var types = [];
+        var result = {};
+        var topcenterCount = 0, bottomcenterCount = 0, leftcenterCount = 0, rightcenterCount = 0;
+        BI.each(devides, function (i, devide) {
+            if (devide.type.indexOf("top-center") > -1) {
+                topcenterCount++;
+            } else if (devide.type.indexOf("bottom-center") > -1) {
+                bottomcenterCount++;
+            } else if (devide.type.indexOf("left-center") > -1) {
+                leftcenterCount++;
+            } else if (devide.type.indexOf("right-center") > -1) {
+                rightcenterCount++;
+            }
+            types.push(devide.type);
+            result[devide.type] = devide;
+        });
+        //drop
+        if (top >= 5 && top <= 15 && left >= 5 && left <= 15 && types.contains("left-top")) {
+            return result["left-top"];
+        }
+        if (top >= 5 && top <= 15 && right >= 5 && right <= 15 && types.contains("top-right")) {
+            return result["top-right"];
+        }
+        if (bottom >= 5 && bottom <= 15 && left >= 5 && left <= 15 && types.contains("bottom-left")) {
+            return result["bottom-left"];
+        }
+        if (bottom >= 5 && bottom <= 15 && right >= 5 && right <= 15 && types.contains("bottom-right")) {
+            return result["bottom-right"];
+        }
+
+        if (top >= 5 && top <= 15 && left >= 25 && left <= 35 && types.contains("top-left")) {
+            return result["top-left"];
+        }
+        if (top >= 5 && top <= 15 && right >= 25 && right <= 35 && types.contains("top-right-second")) {
+            return result["top-right-second"];
+        }
+        if (bottom >= 5 && bottom <= 15 && left >= 25 && left <= 35 && types.contains("bottom-left-second")) {
+            return result["bottom-left-second"];
+        }
+        if (bottom >= 5 && bottom <= 15 && right >= 25 && right <= 35 && types.contains("bottom-right-second")) {
+            return result["bottom-right-second"];
+        }
+
+        //topcenter或bottomcenter
+        if (left >= halfW - 10 && left <= halfW + 10 && (topcenterCount > 0 || bottomcenterCount > 0)) {
+            for (var i = 1; i <= topcenterCount; i++) {
+                var s = (topcenterCount - i) * 20 + 5, e = s + 10;
+                if (top >= s && top <= e) {
+                    return result["top-center" + i];
+                }
+            }
+            for (var i = 1; i <= bottomcenterCount; i++) {
+                var s = (bottomcenterCount - i) * 20 + 5, e = s + 10;
+                if (bottom >= s && bottom <= e) {
+                    return result["bottom-center" + i];
+                }
+            }
+        }
+        //leftcenter或rightcenter
+        if (top >= halfH - 10 && top <= halfH + 10 && (leftcenterCount > 0 || rightcenterCount > 0)) {
+            for (var i = 1; i <= leftcenterCount; i++) {
+                var s = (leftcenterCount - i) * 20 + 5, e = s + 10;
+                if (left >= s && left <= e) {
+                    return result["left-center" + i];
+                }
+            }
+            for (var i = 1; i <= rightcenterCount; i++) {
+                var s = (rightcenterCount - i) * 20 + 5, e = s + 10;
+                if (right >= s && right <= e) {
+                    return result["right-center" + i];
+                }
+            }
+        }
+
+        //缝隙
+        if (top <= 8 && types.contains("top-gap")) {
+            return result["top-gap"];
+        }
+        if (bottom <= 8 && types.contains("bottom-gap")) {
+            return result["bottom-gap"];
+        }
+
+        //三分
+        if (top <= 15 && left >= 15 && right >= 15 && types.contains("top-line")) {
+            return result["top-line"];
+        }
+        if (left <= 15 && top >= 15 && bottom >= 15 && types.contains("left-line")) {
+            return result["left-line"];
+        }
+        if (right <= 15 && top >= 15 && bottom >= 15 && types.contains("right-line")) {
+            return result["right-line"];
+        }
+        if (bottom <= 15 && left >= 15 && right >= 15 && types.contains("bottom-line")) {
+            return result["bottom-line"];
+        }
+
+        //平分
+        if (top <= 1 / 4 * bound.height && types.contains("top")) {
+            return result["top"];
+        }
+        if (top >= 3 / 4 * bound.height && types.contains("bottom")) {
+            return result["bottom"];
+        }
+        if (left <= bound.width / 2 && types.contains("left")) {
+            return result["left"];
+        }
+        return result["right"];
+    },
+
+
+    _getScrollOffset: function () {
+        return {
+            left: this.scrollContainer.element[0].scrollLeft,
+            top: this.scrollContainer.element[0].scrollTop
+        }
+    },
+
+    ////操作////
+    _createOneRegion: function (item) {
+        var el = BI.createWidget(item.el);
+        el.setVisible(true);
+        return {
+            id: el.attr("id"),
+            left: item.left,
+            top: item.top,
+            width: item.width,
+            height: item.height,
+            el: el
+        }
+    },
+
+    _createOneDrop: function (region) {
+        if (this.storeDrops[region.id]) {
+            var drop = this.storeDrops[region.id].el;
+            drop.setVisible(true);
+        } else {
+            var drop = BI.createWidget({
+                type: "bi.layout",
+                cls: "arrangement-drop-region",
+                widgetName: region.id
+            });
+        }
+        return {
+            id: region.id,
+            left: region.left,
+            top: region.top,
+            width: region.width,
+            height: region.height,
+            el: drop
+        }
+    },
+
+    _calculateDrops: function () {
+        var self = this;
+        BI.each(this.drops, function (id, drop) {
+            drop.el.empty();
+            var devides = self._splitRegions(id);
+            var topcenterCount = 0, bottomcenterCount = 0, leftcenterCount = 0, rightcenterCount = 0;
+            var absolutes = [];
+            var horizontals = [];
+            var verticals = [];
+            BI.each(devides, function (i, devide) {
+                if (devide.type.indexOf("top-center") > -1) {
+                    topcenterCount++;
+                } else if (devide.type.indexOf("bottom-center") > -1) {
+                    bottomcenterCount++;
+                } else if (devide.type.indexOf("left-center") > -1) {
+                    leftcenterCount++;
+                } else if (devide.type.indexOf("right-center") > -1) {
+                    rightcenterCount++;
+                }
+            });
+            BI.each(devides, function (i, devide) {
+                switch (devide.type) {
+                    case "left-top":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 5,
+                            top: 5
+                        });
+                        break;
+                    case "top-right":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 5,
+                            top: 5
+                        });
+                        break;
+                    case "bottom-left":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 5,
+                            bottom: 5
+                        });
+                        break;
+                    case "bottom-right":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 5,
+                            bottom: 5
+                        });
+                        break;
+                    case "top-left":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 25,
+                            top: 5
+                        });
+                        break;
+                    case "top-right-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 25,
+                            top: 5
+                        });
+                        break;
+                    case "bottom-left-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 25,
+                            bottom: 5
+                        });
+                        break;
+                    case "bottom-right-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 25,
+                            bottom: 5
+                        });
+                        break;
+                    default:
+                        if (devide.type.indexOf("top-center") > -1) {
+                            var num = devide.type.split("top-center")[1];
+                            horizontals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 20,
+                                    height: 10,
+                                    cls: "drop-devider"
+                                },
+                                tgap: 20 * (topcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("bottom-center") > -1) {
+                            var num = devide.type.split("bottom-center")[1];
+                            horizontals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 20,
+                                    height: 10,
+                                    cls: "drop-devider"
+                                },
+                                bgap: 20 * (bottomcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("left-center") > -1) {
+                            var num = devide.type.split("left-center")[1];
+                            verticals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 10,
+                                    height: 20,
+                                    cls: "drop-devider"
+                                },
+                                lgap: 20 * (leftcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("right-center") > -1) {
+                            var num = devide.type.split("right-center")[1];
+                            verticals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 10,
+                                    height: 20,
+                                    cls: "drop-devider"
+                                },
+                                rgap: 20 * (rightcenterCount - BI.parseInt(num)) + 5
+                            })
+                        }
+                        break;
+                }
+
+            });
+            BI.createWidget({
+                type: "bi.absolute",
+                element: drop.el,
+                items: absolutes
+            });
+
+            BI.createWidget({
+                type: "bi.absolute_horizontal_adapt",
+                element: drop.el,
+                items: horizontals
+            });
+
+            BI.createWidget({
+                type: "bi.absolute_vertical_adapt",
+                element: drop.el,
+                items: verticals
+            });
+        });
+    },
+
+    _applyRegion: function (regions) {
+        var self = this, o = this.options;
+        BI.each(regions || this.regions, function (i, region) {
+            region.el.element.css({
+                left: region.left,
+                top: region.top,
+                width: region.width,
+                height: region.height
+            });
+            self.drops[region.id].left = region.left;
+            self.drops[region.id].top = region.top;
+            self.drops[region.id].width = region.width;
+            self.drops[region.id].height = region.height;
+        });
+        BI.each(this.drops, function (i, region) {
+            region.el.element.css({
+                left: region.left,
+                top: region.top,
+                width: region.width,
+                height: region.height
+            });
+        });
+        this._applyContainer();
+        this._calculateDrops();
+        this.ratio = this.getLayoutRatio();
+    },
+
+    _renderRegion: function () {
+        var self = this;
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: BI.toArray(this.regions)
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.droppable,
+            items: BI.toArray(this.drops)
+        });
+    },
+
+    getClientWidth: function () {
+        return this.scrollContainer.element[0].clientWidth;
+    },
+
+    getClientHeight: function () {
+        return this.scrollContainer.element[0].clientHeight;
+    },
+
+    _applyContainer: function () {
+        //先掩藏后显示能够明确滚动条是否出现
+        this.scrollContainer.element.css("overflow", "hidden");
+        var occupied = this._getRegionOccupied();
+        this.container.element.width(occupied.left + occupied.width).height(occupied.top + occupied.height);
+        this.scrollContainer.element.css("overflow", "auto");
+        return occupied;
+    },
+
+    _modifyRegion: function (regions) {
+        BI.each(this.regions, function (id, region) {
+            if (regions[id]) {
+                region.left = regions[id].left;
+                region.top = regions[id].top;
+                region.width = regions[id].width;
+                region.height = regions[id].height;
+            }
+        });
+        BI.each(this.drops, function (id, region) {
+            if (regions[id]) {
+                region.left = regions[id].left;
+                region.top = regions[id].top;
+                region.width = regions[id].width;
+                region.height = regions[id].height;
+            }
+        });
+    },
+
+    _addRegion: function (item) {
+        var region = this._createOneRegion(item);
+        this.regions[region.id] = region;
+        var drop = this._createOneDrop(region);
+        this.drops[drop.id] = drop;
+        this.storeDrops[drop.id] = drop;
+        this._locationRegion();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [region]
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.droppable,
+            items: [drop]
+        })
+    },
+
+    _deleteRegionByName: function (name) {
+        this.regions[name].el.setVisible(false);
+        this.drops[name].el.setVisible(false);
+        delete this.regions[name];
+        delete this.drops[name];
+        this._locationRegion();
+    },
+
+    _setArrangeSize: function (size) {
+        this.arrangement.element.css({
+            left: size.left,
+            top: size.top,
+            width: size.width,
+            height: size.height
+        })
+    },
+
+    //Grid
+    _getOneWidthPortion: function () {
+        return this.getClientWidth() / BI.Arrangement.PORTION;
+    },
+
+    _getGridPositionAndSize: function (position) {
+        var perWidth = this._getOneWidthPortion();
+        var widthPortion = Math.round(position.width / perWidth);
+        var leftPortion = Math.round(position.left / perWidth);
+        var topPortion = Math.round(position.top / BI.Arrangement.GRID_HEIGHT);
+        var heightPortion = Math.round(position.height / BI.Arrangement.GRID_HEIGHT);
+        // if (leftPortion > BI.Arrangement.PORTION) {
+        //     leftPortion = BI.Arrangement.PORTION;
+        // }
+        // if (widthPortion > BI.Arrangement.PORTION) {
+        //     widthPortion = BI.Arrangement.PORTION;
+        // }
+        // if (leftPortion + widthPortion > BI.Arrangement.PORTION) {
+        //     leftPortion = BI.Arrangement.PORTION - widthPortion;
+        // }
+        if (widthPortion === 0) {
+            widthPortion = 1;
+        }
+        if (heightPortion === 0) {
+            heightPortion = 1;
+        }
+        return {
+            x: leftPortion,
+            y: topPortion,
+            w: widthPortion,
+            h: heightPortion
+        }
+    },
+
+    _getBlockPositionAndSize: function (position) {
+        var perWidth = this._getOneWidthPortion();
+        return {
+            left: position.x * perWidth,
+            top: position.y * BI.Arrangement.GRID_HEIGHT,
+            width: position.w * perWidth,
+            height: position.h * BI.Arrangement.GRID_HEIGHT
+        };
+    },
+
+    _getLayoutsByRegions: function (regions) {
+        var self = this;
+        var result = [];
+        BI.each(regions || this.regions, function (id, region) {
+            result.push(BI.extend(self._getGridPositionAndSize(region), {
+                i: region.id
+            }))
+        });
+        return result;
+    },
+
+    _getLayoutIndexByName: function (layout, name) {
+        return BI.findIndex(layout, function (i, l) {
+            return l.i === name;
+        });
+    },
+
+    _setBlockPositionAndSize: function (size) {
+        this.block.element.css({
+            left: size.left,
+            top: size.top,
+            width: size.width,
+            height: size.height
+        });
+    },
+
+    _getRegionsByLayout: function (layout) {
+        var self = this;
+        var regions = {};
+        BI.each(layout, function (i, ly) {
+            regions[ly.i] = BI.extend(self._getBlockPositionAndSize(ly), {
+                id: ly.i
+            });
+        });
+        return regions;
+    },
+
+    _setRegionsByLayout: function (regions, layout) {
+        var self = this;
+        regions || (regions = this.regions);
+        BI.each(layout, function (i, ly) {
+            if (regions[ly.i]) {
+                BI.extend(regions[ly.i], self._getBlockPositionAndSize(ly));
+            }
+        });
+        return regions;
+    },
+
+    _moveElement: function (layout, l, x, y, isUserAction) {
+        var self = this;
+        if (l.static) return layout;
+
+        if (l.y === y && l.x === x) return layout;
+
+        var movingUp = y && l.y > y;
+        if (typeof x === 'number') l.x = x;
+        if (typeof y === 'number') l.y = y;
+        l.moved = true;
+
+        var sorted = this._sortLayoutItemsByRowCol(layout);
+        if (movingUp) sorted = sorted.reverse();
+        var collisions = getAllCollisions(sorted, l);
+
+        for (var i = 0, len = collisions.length; i < len; i++) {
+            var collision = collisions[i];
+            if (collision.moved) continue;
+
+            if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue;
+
+            if (collision.static) {
+                layout = this._moveElementAwayFromCollision(layout, collision, l, isUserAction);
+            } else {
+                layout = this._moveElementAwayFromCollision(layout, l, collision, isUserAction);
+            }
+        }
+
+        return layout;
+
+        function getAllCollisions(layout, layoutItem) {
+            return BI.filter(layout, function (i, l) {
+                return self._collides(l, layoutItem);
+            });
+        }
+    },
+
+    _sortLayoutItemsByRowCol: function (layout) {
+        return [].concat(layout).sort(function (a, b) {
+            if (a.y > b.y || (a.y === b.y && a.x > b.x)) {
+                return 1;
+            }
+            return -1;
+        });
+    },
+
+    _collides: function (l1, l2) {
+        if (l1 === l2) return false; // same element
+        if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2
+        if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2
+        if (l1.y + l1.h <= l2.y) return false; // l1 is above l2
+        if (l1.y >= l2.y + l2.h) return false; // l1 is below l2
+        return true; // boxes overlap
+    },
+
+    _getFirstCollision: function (layout, layoutItem) {
+        for (var i = 0, len = layout.length; i < len; i++) {
+            if (this._collides(layout[i], layoutItem)) return layout[i];
+        }
+    },
+
+    _moveElementAwayFromCollision: function (layout, collidesWith,
+                                             itemToMove, isUserAction) {
+        if (isUserAction) {
+            var fakeItem = {
+                x: itemToMove.x,
+                y: itemToMove.y,
+                w: itemToMove.w,
+                h: itemToMove.h,
+                i: '-1'
+            };
+            fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0);
+            if (!this._getFirstCollision(layout, fakeItem)) {
+                return this._moveElement(layout, itemToMove, undefined, fakeItem.y);
+            }
+        }
+
+        return this._moveElement(layout, itemToMove, undefined, itemToMove.y + 1);
+    },
+
+    _compactItem: function (compareWith, l, verticalCompact) {
+        if (verticalCompact) {
+            while (l.y > 0 && !this._getFirstCollision(compareWith, l)) {
+                l.y--;
+            }
+        }
+
+        var collides;
+        while ((collides = this._getFirstCollision(compareWith, l))) {
+            l.y = collides.y + collides.h;
+        }
+        return l;
+    },
+
+    compact: function (layout, verticalCompact) {
+        var compareWith = getStatics(layout);
+        var sorted = this._sortLayoutItemsByRowCol(layout);
+        var out = [];
+
+        for (var i = 0, len = sorted.length; i < len; i++) {
+            var l = sorted[i];
+
+            if (!l.static) {
+                l = this._compactItem(compareWith, l, verticalCompact);
+
+                compareWith.push(l);
+            }
+
+            out[layout.indexOf(l)] = l;
+
+            l.moved = false;
+        }
+
+        return out;
+        function getStatics(layout) {
+            return BI.filter(layout, function (i, l) {
+                return l.static;
+            });
+        }
+    },
+
+    ////公有方法////
+    getRegionByName: function (name) {
+        var obj = {};
+        obj[name] = this.regions[name];
+        return this._cloneRegion(obj)[name];
+    },
+
+    getAllRegions: function () {
+        return BI.toArray(this._cloneRegion());
+    },
+
+    getHelper: function () {
+        var helper = BI.createWidget({
+            type: "bi.layout",
+            width: 18,
+            height: 18,
+            cls: "arrangement-helper"
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [helper]
+        });
+        return helper;
+    },
+
+    _start: function (cur) {
+        this.arrangement.setVisible(true);
+        this.droppable.setVisible(true);
+        if (this.options.layoutType === BI.Arrangement.LAYOUT_TYPE.GRID) {
+            this.block.setVisible(true);
+        }
+        BI.each(this.drops, function (i, drop) {
+            drop.el.setVisible(false);
+        });
+        if (cur) {
+            if (this.drops[cur]) {
+                this.drops[cur].el.setVisible(true);
+            }
+        }
+    },
+
+    _stop: function () {
+        this.arrangement.setVisible(false);
+        this.droppable.setVisible(false);
+        this.block.setVisible(false);
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var self = this, result = {};
+        BI.each(direction, function (i, dir) {
+            result[dir] = self._getDirectRelativeRegions(name, [dir]);
+        });
+        return result;
+    },
+
+    ////公有操作////
+    setLayoutType: function (type) {
+        var self = this, o = this.options;
+        if (type !== o.layoutType) {
+            o.layoutType = type;
+            switch (o.layoutType) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    this.relayout();
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    this.relayout();
+                    break;
+            }
+        }
+    },
+
+    getLayoutType: function () {
+        return this.options.layoutType;
+    },
+
+    getLayoutRatio: function () {
+        var occupied = this._getRegionOccupied();
+        var width = this.getClientWidth(), height = this.getClientHeight();
+        return {
+            x: BI.parseFloat(BI.contentFormat((occupied.left + occupied.width) / width, "#.##;-#.##")),
+            y: BI.parseFloat(BI.contentFormat((occupied.top + occupied.height) / height, "#.##;-#.##"))
+        }
+    },
+
+    addRegion: function (region, position) {
+        if (position) {
+            this.setPosition(position, region);
+        }
+        var self = this, o = this.options;
+        if (!this.position) {
+            return false;
+        }
+        var test = this._cloneRegion();
+        BI.each(this.position.regions, function (i, region) {
+            test[region.id].left = region.left;
+            test[region.id].top = region.top;
+            test[region.id].width = region.width;
+            test[region.id].height = region.height;
+
+        });
+        var item = BI.extend({}, region, {
+            left: this.position.insert.left,
+            top: this.position.insert.top,
+            width: this.position.insert.width,
+            height: this.position.insert.height
+        });
+        var added = this._createOneRegion(item);
+        test[added.id] = added;
+        if (this._test(test)) {
+            delete test[added.id];
+            this._modifyRegion(test);
+            this._addRegion(item);
+            this._populate(this.getAllRegions());
+            return true;
+        }
+        return false;
+    },
+
+    deleteRegion: function (name) {
+        if (!this.regions[name]) {
+            return false;
+        }
+        var self = this, o = this.options;
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var clone = this._cloneRegion();
+                var regions = this._getEquivalentRelativeRegions(name);
+                if (regions.length > 0) {
+                    BI.each(regions, function (i, region) {
+                        BI.extend(clone[region.id], region);
+                    });
+                    this._modifyRegion(clone);
+                }
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                this.resize();
+                return true;
+        }
+        return false;
+    },
+
+    setRegionSize: function (name, size) {
+        var self = this, o = this.options;
+        var flag = false;
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var current = this.regions[name];
+                if (size.width !== current.width) {
+                    var regions = this._getInDirectRelativeRegions(name, ["right"]).right;
+                    var lefts = regions.left || [], rights = regions.right || [];
+                    var offset = size.width - current.width;
+                    var cloned = this._cloneRegion();
+                    BI.some(lefts, function (i, left) {
+                        var region = cloned[left.id];
+                        region.width = region.width + offset;
+                    });
+                    BI.some(rights, function (i, right) {
+                        var region = cloned[right.id];
+                        region.width = region.width - offset;
+                        region.left = region.left + offset;
+                    });
+                    if (this._test(cloned) && this._isArrangeFine(cloned)) {
+                        this._modifyRegion(cloned);
+                        flag = true;
+                    }
+                }
+                if (size.height !== current.height) {
+                    var regions = this._getInDirectRelativeRegions(name, ["bottom"]).bottom;
+                    var tops = regions.top || [], bottoms = regions.bottom || [];
+                    var offset = size.height - current.height;
+                    var cloned = this._cloneRegion();
+                    BI.some(tops, function (i, top) {
+                        var region = cloned[top.id];
+                        region.height = region.height + offset;
+                    });
+                    BI.some(bottoms, function (i, bottom) {
+                        var region = cloned[bottom.id];
+                        region.height = region.height - offset;
+                        region.top = region.top + offset;
+                    });
+                    if (this._test(cloned) && this._isArrangeFine(cloned)) {
+                        this._modifyRegion(cloned);
+                        flag = true;
+                    }
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var clone = this._cloneRegion();
+                BI.extend(clone[name], {
+                    width: size.width,
+                    height: size.height
+                });
+                if (this._test(clone)) {
+                    this._modifyRegion(clone);
+                    flag = true;
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var clone = this._cloneRegion();
+                BI.extend(clone[name], {
+                    width: size.width,
+                    height: size.height
+                });
+                if (this._test(clone)) {
+                    var layout = this._getLayoutsByRegions(clone);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    flag = true;
+                }
+                break;
+        }
+        this._locationRegion();
+        this._applyRegion();
+        return flag;
+    },
+
+    setPosition: function (position, size) {
+        var self = this, o = this.options;
+        var insert, regions = [], cur;
+        if (position.left < 0 || position.top < 0) {
+            switch (o.layoutType) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    this.resize();
+                    break;
+            }
+            this._stop();
+            this.position = null;
+            return null;
+        }
+        var offset = this._getScrollOffset();
+        position = {
+            left: position.left + offset.left,
+            top: position.top + offset.top
+        };
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (BI.isEmpty(this.regions)) {
+                    if (self._isPositionInBounds(position, {
+                            left: 0,
+                            top: 0,
+                            width: this.element[0].clientWidth,
+                            height: this.element[0].clientHeight
+                        })) {
+                        insert = {
+                            left: 0,
+                            top: 0,
+                            width: this.element[0].clientWidth,
+                            height: this.element[0].clientHeight
+                        };
+                    }
+                } else {
+                    if (BI.some(this.regions, function (id, region) {
+                            if (self._isPositionInBounds(position, region)) {
+                                var at = self._positionAt(position, region);
+                                if (!at) {
+                                    insert = null;
+                                } else {
+                                    insert = at.insert;
+                                    regions = at.regions;
+                                }
+                                cur = id;
+                                return true;
+                            }
+                        })) {
+                    }
+                    else {
+                        insert = null;
+                        regions = [];
+                    }
+                }
+                if (insert == null) {
+                    this._stop();
+                    self.position = null;
+                    break;
+                }
+
+                this.position = {
+                    insert: insert,
+                    regions: regions
+                };
+                this._setArrangeSize(insert);
+                this._start(cur);
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var insert = {
+                    top: position.top < 0 ? 0 : position.top,
+                    left: position.left < 0 ? 0 : position.left,
+                    width: size.width,
+                    height: size.height
+                };
+                this.position = {
+                    insert: insert
+                };
+                this._setArrangeSize(insert);
+                this._start();
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var p = {
+                    top: position.top < 0 ? 0 : position.top,
+                    left: position.left < 0 ? 0 : position.left,
+                    width: size.width,
+                    height: size.height
+                };
+                this._setArrangeSize(p);
+                var cur = this._getGridPositionAndSize(p);
+                var layout = [{
+                    x: 0, y: BI.MAX, w: cur.w, h: cur.h, i: cur.i
+                }].concat(this._getLayoutsByRegions());
+                layout = this._moveElement(layout, layout[0], cur.x, cur.y, true);
+                layout = this.compact(layout, true);
+                var regions = this._setRegionsByLayout(this._cloneRegion(), layout);
+                var insert = this._getBlockPositionAndSize(layout[0]);
+                this.position = {
+                    insert: insert,
+                    regions: regions
+                };
+                this._applyRegion(regions);
+                this._setBlockPositionAndSize(insert);
+                this._start();
+                break;
+        }
+        return this.position;
+    },
+
+    setRegionPosition: function (name, position) {
+        var self = this, o = this.options;
+        var offset = this._getScrollOffset();
+        position = BI.extend(position, {
+            left: position.left + offset.left,
+            top: position.top + offset.top
+        });
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                BI.extend(this.regions[name], {
+                    left: position.left < 0 ? 0 : position.left,
+                    top: position.top < 0 ? 0 : position.top
+                });
+                this._applyRegion();
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (!position.stop) {
+                    BI.extend(this.regions[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    });
+                    var cloned = this._cloneRegion();
+                    var cur = this._getGridPositionAndSize(BI.extend(cloned[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    }));
+                    var x = cur.x, y = cur.y;
+                    cur = BI.extend(cur, {
+                        x: 0, y: BI.MAX, i: -1
+                    });
+                    delete cloned[name];
+                    var layout = this._getLayoutsByRegions(cloned);
+                    layout = this._moveElement([cur].concat(layout), cur, x, y, true);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._applyRegion();
+
+                    this._setBlockPositionAndSize(this._getBlockPositionAndSize(cur));
+                    this.block.setVisible(true);
+                } else {
+                    BI.extend(this.regions[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    });
+                    var cloned = this._cloneRegion();
+                    var layout = this._getLayoutsByRegions(cloned);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._applyRegion();
+                    this.block.setVisible(false);
+                }
+                break;
+        }
+    },
+
+    setContainerSize: function (size) {
+        var self = this, o = this.options;
+        var occupied = this._getRegionOccupied();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = size.width, height = size.height;
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.width = region.width / occupied.width * width;
+                        //region.height = region.height / occupied.height * height;
+                    });
+                    BI.each(regions, function (id, region) {
+                        var lefts = self.locations[id].left;
+                        var tops = self.locations[id].top;
+                        var bottoms = self.locations[id].bottom;
+                        var maxRegion;
+                        if (lefts.length > 0) {
+                            var ids = self._getRegionNames(lefts);
+                            var rs = self._getRegionsByNames(ids);
+                            maxRegion = self._getRegionOccupied(rs);
+                            region.left = maxRegion.left + maxRegion.width / occupied.width * width;
+                        } else {
+                            region.left = 0;
+                        }
+                        if (bottoms.length === 0) {
+                            region.height = height - region.top;
+                        }
+                        //if (tops.length > 0) {
+                        //    var ids = self._getRegionNames(tops);
+                        //    var rs = self._getRegionsByNames(ids);
+                        //    maxRegion = self._getRegionOccupied(rs);
+                        //    region.top = maxRegion.top + maxRegion.height / occupied.height * height;
+                        //}
+                        //if (tops.length === 0) {
+                        //    region.top = 0;
+                        //}
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+        this.resize();
+    },
+
+    scrollTo: function (top) {
+        this.scrollContainer.element.scrollTop(top);
+    },
+
+    zoom: function (ratio) {
+        var self = this, o = this.options;
+        if (!ratio) {
+            return;
+        }
+        var occupied = this._applyContainer();
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth();
+                    var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width);
+                    //var yRatio = ratio.y * height / (occupied.top + occupied.height);
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.left = region.left * xRatio;
+                        //region.top = region.top * yRatio;
+                        region.width = region.width * xRatio;
+                        //region.height = region.height * yRatio;
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                    this.resize();
+                    // } else {
+                    this.relayout();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth();
+                    var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width);
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.left = region.left * xRatio;
+                        region.width = region.width * xRatio;
+                    });
+                    if (this._test(regions)) {
+                        var layout = this._getLayoutsByRegions(regions);
+                        layout = this.compact(layout, true);
+                        regions = this._getRegionsByLayout(layout);
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                } else {
+                    this.relayout();
+                }
+                break;
+        }
+    },
+
+    resize: function () {
+        var self = this, o = this.options;
+        var occupied = this._applyContainer();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth(), height = this.getClientHeight();
+                    var isHeightAdjust = height > occupied.top + occupied.height;
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.width = region.width / occupied.width * width;
+                        //if (isHeightAdjust) {
+                        //    region.height = region.height / occupied.height * height;
+                        //}
+                    });
+                    BI.each(regions, function (id, region) {
+                        var lefts = self.locations[id].left;
+                        var tops = self.locations[id].top;
+                        var bottoms = self.locations[id].bottom;
+                        var maxRegion;
+                        if (lefts.length > 0) {
+                            var ids = self._getRegionNames(lefts);
+                            var rs = self._getRegionsByNames(ids);
+                            maxRegion = self._getRegionOccupied(rs);
+                            region.left = maxRegion.left + maxRegion.width / occupied.width * width;
+                        } else {
+                            region.left = 0;
+                        }
+                        if (tops.length === 0) {
+                            region.top = 0;
+                        }
+                        if (isHeightAdjust && bottoms.length === 0) {
+                            region.height = height - region.top;
+                        }
+                        //if (isHeightAdjust && tops.length > 0) {
+                        //    var ids = self._getRegionNames(tops);
+                        //    var rs = self._getRegionsByNames(ids);
+                        //    maxRegion = self._getRegionOccupied(rs);
+                        //    region.top = maxRegion.top + maxRegion.height / occupied.height * height;
+                        //}
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                } else {
+                    this.relayout();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.zoom(this.ratio);
+                var regions = this._cloneRegion();
+                var layout = this._getLayoutsByRegions(regions);
+                layout = this.compact(layout, true);
+                regions = this._getRegionsByLayout(layout);
+                this._modifyRegion(regions);
+                this._applyRegion();
+                break;
+        }
+    },
+
+    relayout: function () {
+        var self = this, o = this.options;
+        if (o.isNeedReLayout === false) {
+            return;
+        }
+        //var occupied = this._applyContainer();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (!this._isArrangeFine()) {
+                    var width = this.getClientWidth(), height = this.getClientHeight();
+                    var clone = BI.toArray(this._cloneRegion());
+                    clone.sort(function (r1, r2) {
+                        if (self._isEqual(r1.top, r2.top)) {
+                            return r1.left - r2.left;
+                        }
+                        return r1.top - r2.top;
+                    });
+                    var count = clone.length;
+                    var cols = 3, rows = Math.floor((count - 1) / 3 + 1);
+                    var w = width / cols, h = height / rows;
+                    var store = {};
+                    BI.each(clone, function (i, region) {
+                        var row = Math.floor(i / 3), col = i % 3;
+                        BI.extend(region, {
+                            top: row * 380,
+                            left: col * w,
+                            width: w,
+                            height: 380
+                        });
+                        if (!store[row]) {
+                            store[row] = {};
+                        }
+                        store[row][col] = region;
+                    });
+                    //非3的倍数
+                    if (count % 3 !== 0) {
+                        var lasts = store[rows - 1];
+                        var perWidth = width / (count % 3);
+                        BI.each(lasts, function (i, region) {
+                            BI.extend(region, {
+                                left: BI.parseInt(i) * perWidth,
+                                width: perWidth
+                            });
+                        });
+                    }
+                    if (this._test(clone)) {
+                        this._populate(clone);
+                        this.resize();
+                    }
+                } else {
+                    this.resize();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var width = this.getClientWidth(), height = this.getClientHeight();
+                var regions = this._cloneRegion();
+                var clone = BI.toArray(regions);
+                clone.sort(function (r1, r2) {
+                    if (self._isEqual(r1.top, r2.top)) {
+                        return r1.left - r2.left;
+                    }
+                    return r1.top - r2.top;
+                });
+                var count = clone.length;
+                var cols = 3, rows = Math.floor((count - 1) / 3 + 1);
+                var w = width / cols, h = height / rows;
+                var store = {};
+                BI.each(clone, function (i, region) {
+                    var row = Math.floor(i / 3), col = i % 3;
+                    BI.extend(region, {
+                        top: row * 380,
+                        left: col * w,
+                        width: w,
+                        height: 380
+                    });
+                    if (!store[row]) {
+                        store[row] = {};
+                    }
+                    store[row][col] = region;
+                });
+                //非3的倍数
+                if (count % 3 !== 0) {
+                    var lasts = store[rows - 1];
+                    var perWidth = width / (count % 3);
+                    BI.each(lasts, function (i, region) {
+                        BI.extend(region, {
+                            left: BI.parseInt(i) * perWidth,
+                            width: perWidth
+                        });
+                    });
+                }
+                if (this._test(clone)) {
+                    var layout = this._getLayoutsByRegions(regions);
+                    layout = this.compact(layout, true);
+                    regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._populate(clone);
+                }
+                break;
+        }
+    },
+
+    _populate: function (items) {
+        this._stop();
+        this._calculateRegions(items);
+        this._locationRegion();
+        this._applyRegion();
+    },
+
+    populate: function (items) {
+        var self = this;
+        BI.each(this.regions, function (name, region) {
+            self.regions[name].el.setVisible(false);
+            self.drops[name].el.setVisible(false);
+            delete self.regions[name];
+            delete self.drops[name];
+        });
+        this._populate(items);
+        this._renderRegion();
+    }
+});
+BI.extend(BI.Arrangement, {
+    PORTION: 24,
+    GRID_HEIGHT: 50,
+    LAYOUT_TYPE: {
+        ADAPTIVE: BICst.DASHBOARD_LAYOUT_ADAPT,
+        FREE: BICst.DASHBOARD_LAYOUT_FREE,
+        GRID: BICst.DASHBOARD_LAYOUT_GRID
+    }
+});
+$.shortcut('bi.arrangement', BI.Arrangement);/**
+ * Created by Young's on 2016/4/28.
+ */
+BI.EditorIconCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.EditorIconCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-check-editor-combo",
+            width: 100,
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            allowBlank: true,
+            watermark: "",
+            errorText: ""
+        })
+    },
+
+    _init: function () {
+        BI.EditorIconCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.editor_trigger",
+            items: o.items,
+            height: o.height,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.trigger.on(BI.EditorTrigger.EVENT_CHANGE, function () {
+            self.popup.setValue(this.getValue());
+            self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE);
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.editorIconCheckCombo.hideView();
+            self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editorIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.editorIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.EditorIconCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.editorIconCheckCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.trigger.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.editorIconCheckCombo.populate(items);
+    }
+});
+BI.EditorIconCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.editor_icon_check_combo", BI.EditorIconCheckCombo);/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaCombo
+ * @extend BI.Widget
+ */
+BI.FormulaCombo = BI.inherit(BI.Widget, {
+
+    _constant: {
+        POPUP_HEIGHT: 450,
+        POPUP_WIDTH: 600,
+        POPUP_V_GAP: 10,
+        POPUP_H_GAP: 10,
+        ADJUST_LENGTH: 2,
+        HEIGHT_MAX: 10000,
+        MAX_HEIGHT: 500,
+        MAX_WIDTH: 600,
+        COMBO_TRIGGER_WIDTH: 300
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-combo",
+            height: 30,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FormulaCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.formula_ids = [];
+        this.input = BI.createWidget({
+            type: "bi.formula_combo_trigger",
+            height: o.height,
+            items: o.items
+        });
+        this.formulaPopup = BI.createWidget({
+            type: "bi.formula_combo_popup",
+            fieldItems: o.items
+        });
+
+        this.formulaInputCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: true,
+            isNeedAdjustWidth: false,
+            adjustLength: this._constant.CONDITION_TYPE_COMBO_ADJUST,
+            el: this.input,
+            popup: {
+                el: {
+                    type: "bi.absolute",
+                    height: this._constant.HEIGHT_MAX,
+                    width: this._constant.POPUP_WIDTH,
+                    items: [{
+                        el: this.formulaPopup,
+                        top: this._constant.POPUP_V_GAP,
+                        left: this._constant.POPUP_H_GAP,
+                        right: this._constant.POPUP_V_GAP,
+                        bottom: 0
+                    }]
+                },
+                stopPropagation: false,
+                maxHeight: this._constant.MAX_HEIGHT,
+                width: this._constant.MAX_WIDTH
+            }
+        });
+        this.formulaInputCombo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.formulaPopup.setValue(self.input.getValue());
+        });
+        this.formulaPopup.on(BI.FormulaComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.formulaPopup.getValue());
+            self.formulaInputCombo.hideView();
+            self.fireEvent(BI.FormulaCombo.EVENT_CHANGE);
+        });
+        this.formulaPopup.on(BI.FormulaComboPopup.EVENT_VALUE_CANCEL, function () {
+            self.formulaInputCombo.hideView();
+        });
+    },
+
+    setValue: function (v) {
+        if (this.formulaInputCombo.isViewVisible()) {
+            this.formulaInputCombo.hideView();
+        }
+        this.input.setValue(v);
+        this.input.setText(BI.Func.getFormulaStringFromFormulaValue(v));
+        this.formulaPopup.setValue(this.input.getValue());
+    },
+
+    getFormulaTargetIds: function() {
+        return this.formulaPopup.getFormulaTargetIds();
+    },
+
+    getValue: function () {
+        return this.input.getValue();
+    }
+});
+BI.FormulaCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_combo", BI.FormulaCombo);/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaComboPopup
+ * @extend BI.Widget
+ */
+BI.FormulaComboPopup = BI.inherit(BI.Widget, {
+
+    _constant: {
+        BUTTON_HEIGHT: 30,
+        SOUTH_HEIGHT: 60,
+        SOUTH_H_GAP: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-pane-popup"
+        })
+    },
+
+    _init: function () {
+        BI.FormulaComboPopup.superclass._init.apply(this, arguments);
+        this.populate();
+    },
+
+    populate: function () {
+        var self = this, fieldItems = this.options.fieldItems;
+        this.formula = BI.createWidget({
+            type: "bi.formula_insert"
+        });
+        this.formula.populate(fieldItems);
+        var confirmButton = BI.createWidget({
+            type: "bi.button",
+            level: "common",
+            height: this._constant.BUTTON_HEIGHT,
+            text: BI.i18nText("BI-Basic_OK")
+        });
+        var cancelButton = BI.createWidget({
+            type: "bi.button",
+            level: "ignore",
+            height: this._constant.BUTTON_HEIGHT,
+            text: BI.i18nText("BI-Basic_Cancel")
+        });
+
+        this.formula.on(BI.FormulaInsert.EVENT_CHANGE, function () {
+            confirmButton.setEnable(self.formula.checkValidation());
+        });
+        confirmButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FormulaComboPopup.EVENT_CHANGE);
+        });
+        cancelButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.setValue(self.oldValue);
+            self.fireEvent(BI.FormulaComboPopup.EVENT_VALUE_CANCEL);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.formula,
+                height: "fill"
+            }, {
+                el: {
+                    type: "bi.right_vertical_adapt",
+                    height: this._constant.SOUTH_HEIGHT,
+                    items: [cancelButton, confirmButton],
+                    hgap: this._constant.SOUTH_H_GAP
+                },
+                height: this._constant.SOUTH_HEIGHT
+            }]
+        })
+    },
+
+    getFormulaTargetIds: function(){
+        return this.formula.getUsedFields();
+    },
+
+    getValue: function () {
+        return this.formula.getValue();
+    },
+
+    setValue: function (v) {
+        this.oldValue = v;
+        this.formula.setValue(v);
+    }
+});
+BI.FormulaComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FormulaComboPopup.EVENT_VALUE_CANCEL = "EVENT_VALUE_CANCEL";
+$.shortcut("bi.formula_combo_popup", BI.FormulaComboPopup);/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaComboTrigger
+ * @extend BI.Widget
+ */
+BI.FormulaComboTrigger = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaComboTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-combo-trigger",
+            height: 30,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FormulaComboTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.label = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            textHeight: this.options.height,
+            lgap: 10
+        });
+    },
+
+    _getTextFromFormulaValue: function (formulaValue) {
+        var self = this;
+        var formulaString = "";
+        var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)/g;
+        var result = formulaValue.match(regx);
+        BI.each(result, function (i, item) {
+            var fieldRegx = /\$[\{][^\}]*[\}]/;
+            var str = item.match(fieldRegx);
+            if (BI.isNotEmptyArray(str)) {
+                var id = str[0].substring(2, item.length - 1);
+                var item = BI.find(self.options.items, function (i, item) {
+                    return id === item.value;
+                });
+                formulaString = formulaString + item.text;
+            } else {
+                formulaString = formulaString + item;
+            }
+        });
+        return formulaString;
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    setValue: function (v) {
+        this.options.value = v;
+        this.label.setText(this._getTextFromFormulaValue(v));
+    }
+});
+$.shortcut("bi.formula_combo_trigger", BI.FormulaComboTrigger);/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconCombo
+ * @extend BI.Widget
+ */
+BI.IconCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-icon-combo",
+            width: 24,
+            height: 24,
+            iconClass: "",
+            el: {},
+            popup: {},
+            minWidth: 100,
+            maxWidth: 'auto',
+            maxHeight: 300,
+            direction: "bottom",
+            adjustLength: 3,//调整的距离
+            adjustXOffset: 0,
+            adjustYOffset: 0,
+            offsetStyle: "left",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        })
+    },
+
+    _init: function () {
+        BI.IconCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.icon_combo_trigger",
+            iconClass: o.iconClass,
+            title: o.title,
+            items: o.items,
+            width: o.width,
+            height: o.height,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight
+        });
+        this.popup = BI.createWidget(o.popup, {
+            type: "bi.icon_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.IconComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.iconCombo.hideView();
+            self.fireEvent(BI.IconCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.iconCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            direction: o.direction,
+            adjustLength: o.adjustLength,
+            adjustXOffset: o.adjustXOffset,
+            adjustYOffset: o.adjustYOffset,
+            offsetStyle: o.offsetStyle,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxWidth: o.maxWidth,
+                maxHeight: o.maxHeight,
+                minWidth: o.minWidth
+            }
+        });
+    },
+
+    showView: function () {
+        this.iconCombo.showView();
+    },
+
+    hideView: function () {
+        this.iconCombo.hideView();
+    },
+
+    setValue: function (v) {
+        this.iconCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.IconCombo.superclass.setEnable.apply(this, arguments);
+        this.iconCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.iconCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.iconCombo.populate(items);
+    }
+});
+BI.IconCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo", BI.IconCombo);/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconComboPopup
+ * @extend BI.Pane
+ */
+BI.IconComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi.icon-combo-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.IconComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.single_select_icon_text_item",
+                height: 30
+            }),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.IconComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    populate: function (items) {
+        BI.IconComboPopup.superclass.populate.apply(this, arguments);
+        items = BI.createItems(items, {
+            type: "bi.single_select_icon_text_item",
+            height: 30
+        });
+        this.popup.populate(items);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.IconComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo_popup", BI.IconComboPopup);/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconComboTrigger
+ * @extend BI.Widget
+ */
+BI.IconComboTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconComboTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-icon-combo-trigger",
+            el: {},
+            items: [],
+            iconClass: "",
+            width: 25,
+            height: 25,
+            isShowDown: true
+        });
+    },
+
+    _init: function () {
+        BI.IconComboTrigger.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.button = BI.createWidget(o.el, {
+            type: "bi.icon_change_button",
+            cls: "icon-combo-trigger-icon " + o.iconClass,
+            disableSelected: true,
+            width: o.width,
+            height: o.height,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight
+        });
+        this.down = BI.createWidget({
+            type: "bi.icon_button",
+            disableSelected: true,
+            cls: "icon-combo-down-icon trigger-triangle-font",
+            width: 12,
+            height: 8
+        });
+        this.down.setVisible(o.isShowDown);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.button,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.down,
+                right: 0,
+                bottom: 0
+            }]
+        });
+        if (BI.isKey(o.value)) {
+            this.setValue(o.value);
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options;
+        this.options.items = items || [];
+        this.button.setIcon(o.iconClass);
+        this.button.setSelected(false);
+        this.down.setSelected(false);
+    },
+
+    setValue: function (v) {
+        BI.IconComboTrigger.superclass.setValue.apply(this, arguments);
+        var o = this.options;
+        var iconClass = "";
+        v = BI.isArray(v) ? v[0] : v;
+        if (BI.any(this.options.items, function (i, item) {
+                if (v === item.value) {
+                    iconClass = item.iconClass;
+                    return true;
+                }
+            })) {
+            this.button.setIcon(iconClass);
+            this.button.setSelected(true);
+            this.down.setSelected(true);
+        } else {
+            this.button.setIcon(o.iconClass);
+            this.button.setSelected(false);
+            this.down.setSelected(false);
+        }
+    }
+});
+BI.IconComboTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo_trigger", BI.IconComboTrigger);/**
+ * 单选combo
+ *
+ * @class BI.StaticCombo
+ * @extend BI.Widget
+ */
+BI.StaticCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.StaticCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-static-combo",
+            height: 30,
+            text: "",
+            el: {},
+            items: [],
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        })
+    },
+
+    _init: function () {
+        BI.StaticCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.text_icon_item",
+            cls: "bi-select-text-trigger pull-down-font",
+            text: o.text,
+            readonly: true,
+            textLgap: 5,
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            textAlign: o.textAlign,
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.combo.hideView();
+            self.fireEvent(BI.StaticCombo.EVENT_CHANGE, arguments);
+        });
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+
+    getValue: function () {
+        return this.combo.getValue();
+    }
+});
+BI.StaticCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.static_combo", BI.StaticCombo);/**
+ * @class BI.TextValueCheckCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : check + text
+ */
+BI.TextValueCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-text-value-check-combo",
+            width: 100,
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextValueCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.textIconCheckCombo.hideView();
+            self.fireEvent(BI.TextValueCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.textIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setTitle: function (title) {
+        this.trigger.setTitle(title);
+    },
+
+    setValue: function (v) {
+        this.textIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.textIconCheckCombo.setEnable(v);
+    },
+
+    setWarningTitle: function (title) {
+        this.trigger.setWarningTitle(title);
+    },
+
+    getValue: function () {
+        return this.textIconCheckCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.textIconCheckCombo.populate(items);
+    }
+});
+BI.TextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_check_combo", BI.TextValueCheckCombo);/**
+ * @class BI.SmallTextValueCheckCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : check + text
+ */
+BI.SmallTextValueCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SmallTextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            width: 100,
+            height: 24,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.SmallTextValueCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.small_select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.SmallTextIconCheckCombo.hideView();
+            self.fireEvent(BI.SmallTextValueCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.SmallTextIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.SmallTextIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.SmallTextValueCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.SmallTextIconCheckCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.SmallTextIconCheckCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.SmallTextIconCheckCombo.populate(items);
+    }
+});
+BI.SmallTextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.small_text_value_check_combo", BI.SmallTextValueCheckCombo);BI.TextValueCheckComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCheckComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-icon-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.TextValueCheckComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: this._formatItems(o.items),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.TextValueCheckComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    _formatItems: function (items) {
+        return BI.map(items, function (i, item) {
+            return BI.extend({
+                type: "bi.icon_text_item",
+                cls: "item-check-font bi-list-item",
+                height: 30
+            }, item);
+        });
+    },
+
+    populate: function (items) {
+        BI.TextValueCheckComboPopup.superclass.populate.apply(this, arguments);
+        this.popup.populate(this._formatItems(items));
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.TextValueCheckComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_check_combo_popup", BI.TextValueCheckComboPopup);/**
+ * @class BI.TextValueCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.TextValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-text-value-combo",
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: "",
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.TextValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.textIconCombo.hideView();
+            self.fireEvent(BI.TextValueCombo.EVENT_CHANGE, arguments);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.textIconCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.textIconCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueCombo.superclass.setEnable.apply(this, arguments);
+        this.textIconCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.textIconCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.textIconCombo.populate(items);
+    }
+});
+BI.TextValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_combo", BI.TextValueCombo);/**
+ * @class BI.SmallTextValueCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.SmallTextValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SmallTextValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            width: 100,
+            height: 24,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            el: {},
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.SmallTextValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.small_select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.SmallTextValueCombo.hideView();
+            self.fireEvent(BI.SmallTextValueCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.SmallTextValueCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.SmallTextValueCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.SmallTextValueCombo.superclass.setEnable.apply(this, arguments);
+        this.SmallTextValueCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.SmallTextValueCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.SmallTextValueCombo.populate(items);
+    }
+});
+BI.SmallTextValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.small_text_value_combo", BI.SmallTextValueCombo);BI.TextValueComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-icon-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.TextValueComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.single_select_item",
+                textAlign: o.textAlign,
+                height: 30
+            }),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.TextValueComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    populate: function (items) {
+        BI.TextValueComboPopup.superclass.populate.apply(this, arguments);
+        items = BI.createItems(items, {
+            type: "bi.single_select_item",
+            height: 30
+        });
+        this.popup.populate(items);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.TextValueComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_combo_popup", BI.TextValueComboPopup);/**
+ * @class BI.TextValueDownListCombo
+ * @extend BI.Widget
+ */
+BI.TextValueDownListCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueDownListCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-value-down-list-combo",
+            height: 30,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextValueDownListCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this._createValueMap();
+
+        this.trigger = BI.createWidget({
+            type: "bi.down_list_select_text_trigger",
+            height: o.height,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.down_list_combo",
+            element: this,
+            chooseType: BI.Selection.Single,
+            adjustLength: 2,
+            height: o.height,
+            el: this.trigger,
+            items: BI.deepClone(o.items)
+        });
+
+        this.combo.on(BI.DownListCombo.EVENT_CHANGE, function () {
+            self.setValue(self.combo.getValue()[0].value);
+            self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE);
+        });
+
+        this.combo.on(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, function () {
+            self.setValue(self.combo.getValue()[0].childValue);
+            self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE);
+        });
+    },
+
+    _createValueMap: function () {
+        var self = this;
+        this.valueMap = {};
+        BI.each(BI.flatten(this.options.items), function (idx, item) {
+            if (BI.has(item, "el")) {
+                BI.each(item.children, function (id, it) {
+                    self.valueMap[it.value] = {value: item.el.value, childValue: it.value}
+                });
+            } else {
+                self.valueMap[item.value] = {value: item.value};
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = this.valueMap[v];
+        this.combo.setValue([v]);
+        this.trigger.setValue(v.childValue || v.value);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueDownListCombo.superclass.setEnable.apply(this, arguments);
+        this.combo.setEnable(v);
+    },
+
+    getValue: function () {
+        var v = this.combo.getValue()[0];
+        return [v.childValue || v.value];
+    },
+
+    populate: function (items) {
+        this.options.items = BI.flatten(items);
+        this.combo.populate(items);
+        this._createValueMap();
+    }
+});
+BI.TextValueDownListCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_down_list_combo", BI.TextValueDownListCombo);/**
+ * 选择字段trigger, downlist专用
+ * 显示形式为 父亲值(儿子值)
+ *
+ * @class BI.DownListSelectTextTrigger
+ * @extends BI.Trigger
+ */
+BI.DownListSelectTextTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListSelectTextTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-select-text-trigger",
+            height: 24,
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.DownListSelectTextTrigger.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            element: this,
+            height: o.height,
+            items: this._formatItemArray(o.items),
+            text: o.text
+        });
+    },
+
+    _formatItemArray: function(){
+        var sourceArray = BI.flatten(BI.deepClone(this.options.items));
+        var targetArray = [];
+        BI.each(sourceArray, function(idx, item){
+            if(BI.has(item, "el")){
+                BI.each(item.children, function(id, it){
+                    it.text = item.el.text + "(" + it.text + ")";
+                });
+                targetArray = BI.concat(targetArray, item.children);
+            }else{
+                targetArray.push(item);
+            }
+        });
+        return targetArray;
+    },
+
+    setValue: function (vals) {
+        this.trigger.setValue(vals);
+    },
+
+    populate: function (items) {
+        this.trigger.populate(this._formatItemArray(items));
+    }
+});
+$.shortcut("bi.down_list_select_text_trigger", BI.DownListSelectTextTrigger);/**
+ * 根据内容自适应长度的输入框
+ * @class BI.AdaptiveEditor
+ * @extends BI.Single
+ */
+BI.AdaptiveEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.AdaptiveEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-adapt-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.AdaptiveEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            element: this,
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_BLUR, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CLICK, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self._checkEditorLength();
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ENTER, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.SignEditor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.SignEditor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_EMPTY);
+        });
+        this._checkEditorLength();
+    },
+
+    _checkEditorLength: function () {
+        var o = this.options;
+        this.element.width(BI.DOM.getTextSizeWidth(this.getValue(), 14) + 2 * o.hgap + o.lgap + o.rgap);
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+        this._checkEditorLength();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.editor.getState();
+    },
+
+    setState: function (v) {
+
+    }
+});
+BI.AdaptiveEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.AdaptiveEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.AdaptiveEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.AdaptiveEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.AdaptiveEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.AdaptiveEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.AdaptiveEditor.EVENT_START = "EVENT_START";
+BI.AdaptiveEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.AdaptiveEditor.EVENT_STOP = "EVENT_STOP";
+BI.AdaptiveEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.AdaptiveEditor.EVENT_VALID = "EVENT_VALID";
+BI.AdaptiveEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.AdaptiveEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.AdaptiveEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.AdaptiveEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.AdaptiveEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.adapt_editor", BI.AdaptiveEditor);/**
+ * 有清楚按钮的文本框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallTextEditor
+ * @extends BI.SearchEditor
+ */
+BI.ClearEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.ClearEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-clear-editor",
+            height: 30,
+            errorText: "",
+            watermark: "",
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn
+        });
+    },
+    _init: function () {
+        BI.ClearEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            watermark: o.watermark,
+            allowBlank: true,
+            errorText: o.errorText,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker
+        });
+        this.clear = BI.createWidget({
+            type: "bi.icon_button",
+            stopEvent: true,
+            cls: "search-close-h-font"
+        });
+        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.setValue("");
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
+            self.fireEvent(BI.ClearEditor.EVENT_CLEAR);
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    el: this.editor
+                },
+                {
+                    el: this.clear,
+                    width: 25
+                }]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self._checkClear();
+            self.fireEvent(BI.ClearEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.ClearEditor.EVENT_KEY_DOWN, v);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_SPACE)
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_BACKSPACE)
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_VALID)
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_ERROR)
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_RESTRICT)
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self._checkClear();
+            self.fireEvent(BI.ClearEditor.EVENT_EMPTY)
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_REMOVE)
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_CONFIRM)
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_STOP);
+        });
+
+        this.clear.invisible();
+    },
+
+    _checkClear: function () {
+        if (!this.getValue()) {
+            this.clear.invisible();
+        } else {
+            this.clear.visible();
+        }
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    getValue: function () {
+        if (this.isValid()) {
+            var res = this.editor.getValue().match(/[\S]+/g);
+            return BI.isNull(res) ? "" : res[res.length - 1];
+        }
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+        if (BI.isKey(v)) {
+            this.clear.visible();
+        }
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    }
+});
+BI.ClearEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.ClearEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.ClearEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.ClearEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.ClearEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.ClearEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.ClearEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+BI.ClearEditor.EVENT_CLEAR = "EVENT_CLEAR";
+
+BI.ClearEditor.EVENT_START = "EVENT_START";
+BI.ClearEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.ClearEditor.EVENT_STOP = "EVENT_STOP";
+BI.ClearEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.ClearEditor.EVENT_VALID = "EVENT_VALID";
+BI.ClearEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.ClearEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.ClearEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.ClearEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.ClearEditor.EVENT_EMPTY = "EVENT_EMPTY";
+$.shortcut("bi.clear_editor", BI.ClearEditor);/**
+ * Created by roy on 15/9/14.
+ */
+BI.SearchEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.SearchEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-search-editor",
+            height: 30,
+            errorText: "",
+            watermark: BI.i18nText("BI-Basic_Search"),
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn
+        });
+    },
+    _init: function () {
+        this.options.height -= 2;
+        BI.SearchEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            watermark: o.watermark,
+            allowBlank: true,
+            errorText: o.errorText,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker
+        });
+        this.clear = BI.createWidget({
+            type: "bi.icon_button",
+            stopEvent: true,
+            cls: "search-close-h-font"
+        });
+        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.setValue("");
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
+            self.fireEvent(BI.SearchEditor.EVENT_CLEAR);
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    el: {
+                        type: "bi.center_adapt",
+                        cls: "search-font",
+                        items: [{
+                            el: {
+                                type: "bi.icon"
+                            }
+                        }]
+                    },
+                    width: 25
+                },
+                {
+                    el: self.editor
+                },
+                {
+                    el: this.clear,
+                    width: 25
+                }
+            ]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self._checkClear();
+            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SearchEditor.EVENT_KEY_DOWN, v);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_SPACE)
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_BACKSPACE)
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_VALID)
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_ERROR)
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_RESTRICT)
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self._checkClear();
+            self.fireEvent(BI.SearchEditor.EVENT_EMPTY)
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_REMOVE)
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_CONFIRM)
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_STOP);
+        });
+
+        this.clear.invisible();
+    },
+
+    _checkClear: function () {
+        if (!this.getValue()) {
+            this.clear.invisible();
+        } else {
+            this.clear.visible();
+        }
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    getValue: function () {
+        if (this.isValid()) {
+            var res = this.editor.getValue().match(/[\S]+/g);
+            return BI.isNull(res) ? "" : res[res.length - 1];
+        }
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+        if (BI.isKey(v)) {
+            this.clear.visible();
+        }
+    },
+
+    setValid: function (b) {
+        this.editor.setValid(b);
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setEnable: function (b) {
+        BI.Editor.superclass.setEnable.apply(this, arguments);
+        this.editor && this.editor.setEnable(b);
+        this.clear.setEnabled(b);
+    }
+});
+BI.SearchEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SearchEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SearchEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SearchEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SearchEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SearchEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SearchEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+BI.SearchEditor.EVENT_CLEAR = "EVENT_CLEAR";
+
+BI.SearchEditor.EVENT_START = "EVENT_START";
+BI.SearchEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SearchEditor.EVENT_STOP = "EVENT_STOP";
+BI.SearchEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SearchEditor.EVENT_VALID = "EVENT_VALID";
+BI.SearchEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SearchEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SearchEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SearchEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.SearchEditor.EVENT_EMPTY = "EVENT_EMPTY";
+$.shortcut("bi.search_editor", BI.SearchEditor);/**
+ * 小号搜索框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallSearchEditor
+ * @extends BI.SearchEditor
+ */
+BI.SmallSearchEditor = BI.inherit(BI.SearchEditor, {
+    _defaultConfig: function () {
+        var conf = BI.SmallSearchEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-small-search-editor",
+            height: 24
+        });
+    },
+
+    _init: function () {
+        BI.SmallSearchEditor.superclass._init.apply(this, arguments);
+    }
+});
+$.shortcut("bi.small_search_editor", BI.SmallSearchEditor);/**
+ * sign是新值(初始value值)形式的自适应宽度的输入框
+ * @class BI.SignInitialEditor
+ * @extends BI.Single
+ */
+BI.SignInitialEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.SignInitialEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-sign-initial-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            value: "",
+            text: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SignInitialEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            element: this,
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value || o.text,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        if(BI.isNotNull(o.value)){
+            this.setState(o.value);
+        }
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SignInitialEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            self.setState(self.editor.getValue());
+            self.fireEvent(BI.SignInitialEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.SignEditor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.SignEditor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_EMPTY);
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v.value);
+        this.setState(v.value);
+    },
+
+    getValue: function () {
+        return {
+            value: this.editor.getValue(),
+            text: this.options.text
+        }
+    },
+
+    getState: function () {
+        return this.editor.getState();
+    },
+
+    setState: function (v) {
+        var o = this.options;
+        v = (BI.isEmpty(v) || v == o.text) ? o.text : v + "(" + o.text + ")";
+        this.editor.setState(v);
+    }
+});
+BI.SignInitialEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SignInitialEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SignInitialEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SignInitialEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SignInitialEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SignInitialEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SignInitialEditor.EVENT_START = "EVENT_START";
+BI.SignInitialEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SignInitialEditor.EVENT_STOP = "EVENT_STOP";
+BI.SignInitialEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SignInitialEditor.EVENT_VALID = "EVENT_VALID";
+BI.SignInitialEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SignInitialEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SignInitialEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SignInitialEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SignInitialEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.sign_initial_editor", BI.SignInitialEditor);/**
+ * sign标签分两段,可以自定义样式
+ * @class BI.SignStyleEditor
+ * @extends BI.Single
+ */
+BI.SignStyleEditor = BI.inherit(BI.Single, {
+
+    constants: {
+        tipTextGap: 4
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.SignStyleEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-sign-style-editor",
+            text: "",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: false,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SignStyleEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "sign-style-editor-text",
+            textAlign: "left",
+            height: o.height,
+            hgap: 4,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.selectAll();
+            }
+        });
+
+        this.tipText = BI.createWidget({
+            type: "bi.text_button",
+            cls: "sign-style-editor-tip",
+            textAlign: "right",
+            rgap: 4,
+            height: o.height,
+            text: o.text,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.selectAll();
+            }
+        });
+
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SignStyleEditor.EVENT_CLICK_LABEL)
+            });
+        });
+
+        this.tipText.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SignStyleEditor.EVENT_CLICK_LABEL)
+            });
+        });
+
+        this.wrap = BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [this.text, this.tipText]
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SignStyleEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self._checkText();
+            self._resizeLayout();
+            self.fireEvent(BI.SignStyleEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_EMPTY);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+        this._checkText();
+
+        BI.nextTick(function () {
+            var tipTextSize = self.text.element.getStyle("font-size");
+            self.tipTextSize = tipTextSize.substring(0, tipTextSize.length - 2);
+            self._resizeLayout();
+        });
+    },
+
+    _checkText: function () {
+        var o = this.options;
+        if (this.editor.getValue() === "") {
+            this.text.setValue(o.watermark || "");
+            this.text.element.addClass("bi-water-mark");
+        } else {
+            this.text.setValue(this.editor.getValue());
+            this.tipText.setValue("(" + o.text + ")");
+            this.text.element.removeClass("bi-water-mark");
+        }
+        this.setTitle(this.text.getValue() + this.tipText.getValue());
+    },
+
+    _showInput: function () {
+        this.editor.setVisible(true);
+        this.text.setVisible(false);
+        this.tipText.setVisible(false);
+    },
+
+    _showHint: function () {
+        this.editor.setVisible(false);
+        this.text.setVisible(true);
+        this.tipText.setVisible(true);
+    },
+
+    _resizeLayout: function () {
+        this.wrap.attr("items")[0].width = BI.DOM.getTextSizeWidth(this.text.getValue(), this.tipTextSize) + 2 * this.constants.tipTextGap;
+        this.wrap.resize();
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+        this._checkText();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (k) {
+        BI.SignStyleEditor.superclass.setValue.apply(this, arguments);
+        this.editor.setValue(k);
+        this._checkText();
+        this._resizeLayout();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.options.text;
+    },
+
+    setState: function (v) {
+        var o = this.options;
+        o.text = v;
+        this._showHint();
+        this.tipText.setValue("(" + v + ")");
+        this._checkText();
+    }
+});
+BI.SignStyleEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SignStyleEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SignStyleEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SignStyleEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SignStyleEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SignStyleEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SignStyleEditor.EVENT_START = "EVENT_START";
+BI.SignStyleEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SignStyleEditor.EVENT_STOP = "EVENT_STOP";
+BI.SignStyleEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SignStyleEditor.EVENT_VALID = "EVENT_VALID";
+BI.SignStyleEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SignStyleEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SignStyleEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SignStyleEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SignStyleEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.sign_style_editor", BI.SignStyleEditor);/**
+ * guy
+ * @class BI.TextEditor
+ * @extends BI.Single
+ */
+BI.TextEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.TextEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-text-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: false,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.TextEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isNumber(o.height)) {
+            this.element.css({height: o.height - 2});
+        }
+        if (BI.isNumber(o.width)) {
+            this.element.css({width: o.width - 2});
+        }
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height - 2,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.TextEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.TextEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_KEY_DOWN);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_BACKSPACE);
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.TextEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_REMOVE);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.TextEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.TextEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.TextEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.TextEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.TextEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.TextEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.TextEditor.EVENT_EMPTY);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    setEnable: function (b) {
+        BI.Editor.superclass.setEnable.apply(this, arguments);
+        this.editor && this.editor.setEnable(b);
+    }
+});
+BI.TextEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.TextEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.TextEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.TextEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.TextEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.TextEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.TextEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+
+BI.TextEditor.EVENT_START = "EVENT_START";
+BI.TextEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.TextEditor.EVENT_STOP = "EVENT_STOP";
+BI.TextEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.TextEditor.EVENT_VALID = "EVENT_VALID";
+BI.TextEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.TextEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.TextEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.TextEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.TextEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.text_editor", BI.TextEditor);/**
+ * 小号搜索框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallTextEditor
+ * @extends BI.SearchEditor
+ */
+BI.SmallTextEditor = BI.inherit(BI.TextEditor, {
+    _defaultConfig: function () {
+        var conf = BI.SmallTextEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-small-text-editor",
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.SmallTextEditor.superclass._init.apply(this, arguments);
+    }
+});
+$.shortcut("bi.small_text_editor", BI.SmallTextEditor);/**
+ * @class BI.LoadingCancelMask
+ * @extend BI.Widget
+ * 带有取消按钮的正在加载mask
+ */
+BI.LoadingCancelMask = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingCancelMask.superclass._defaultConfig.apply(this, arguments), {})
+    },
+
+    _init: function () {
+        BI.LoadingCancelMask.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var cancelButton = BI.createWidget({
+            type: "bi.button",
+            level: "ignore",
+            width: 100,
+            height: 30,
+            text: BI.i18nText("BI-Basic_Cancel")
+        });
+        cancelButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.fireEvent(BI.LoadingCancelMask.EVENT_VALUE_CANCEL);
+            self.destroy();
+        });
+        var mask = BI.Maskers.create(this.getName(), o.masker);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: mask,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    cls: "bi-loading-main-background"
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }, {
+                el: {
+                    type: "bi.center_adapt",
+                    cls: "bi-loading-mask-content",
+                    items: [{
+                        el: {
+                            type: "bi.vertical",
+                            items: [{
+                                type: "bi.center_adapt",
+                                cls: "loading-bar-icon",
+                                items: [{
+                                    type: "bi.icon",
+                                    width: 208,
+                                    height: 30
+                                }]
+                            }, {
+                                type: "bi.label",
+                                cls: "loading-bar-label",
+                                text: o.text,
+                                height: 30
+                            }, {
+                                type: "bi.center_adapt",
+                                items: [cancelButton]
+                            }],
+                            vgap: 10
+                        }
+                    }]
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+BI.LoadingCancelMask.EVENT_VALUE_CANCEL = "EVENT_VALUE_CANCEL";
+$.shortcut("bi.loading_cancel_mask", BI.LoadingCancelMask);/**
+ * @class BI.LoadingBackground
+ * @extend BI.Widget
+ * 正在加载mask层
+ */
+BI.LoadingBackground = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingBackground.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "",
+            backgroundCls: "loading-background-e50"
+        })
+    },
+
+    _init: function () {
+        BI.LoadingBackground.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var mask = BI.Maskers.create(this.getName(), o.masker, {offset: o.offset, container: o.container});
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: mask,
+            cls: "bi-loading-mask " + o.backgroundCls
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+$.shortcut("bi.loading_background", BI.LoadingBackground);/**
+ * @class BI.LoadingMask
+ * @extend BI.Widget
+ * 正在加载mask层
+ */
+BI.LoadingMask = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingMask.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: ""
+        });
+    },
+
+    _init: function () {
+        BI.LoadingMask.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var mask = BI.Maskers.create(this.getName(), o.masker, {offset: o.offset, container: o.container});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: mask,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    cls: "bi-loading-main-background"
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }, {
+                el: {
+                    type: "bi.center_adapt",
+                    cls: "bi-loading-mask-content",
+                    items: [{
+                        type: "bi.vertical",
+                        items: [{
+                            type: "bi.center_adapt",
+                            cls: "loading-bar-icon",
+                            items: [{
+                                type: "bi.icon",
+                                width: 208,
+                                height: 30
+                            }]
+                        }, {
+                            type: "bi.label",
+                            cls: "loading-bar-label",
+                            text: o.text,
+                            height: 30
+                        }]
+                    }]
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+$.shortcut("bi.loading_mask", BI.LoadingMask);/**
+ * 一个button选中的时候下面有条线
+ *
+ * Created by GUY on 2015/9/30.
+ * @class BI.LineSegmentButton
+ * @extends BI.BasicButton
+ */
+BI.LineSegmentButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function() {
+        var conf = BI.LineSegmentButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            baseCls : (conf.baseCls ||"")+' bi-line-segment-button bi-list-item-effect',
+            once: true,
+            readonly: true,
+            hgap: 10,
+            height: 25
+        })
+    },
+
+    _init:function() {
+        BI.LineSegmentButton.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            text: o.text,
+            height: o.height,
+            value: o.value,
+            hgap: o.hgap
+        });
+
+        this.line = BI.createWidget({
+            type: "bi.layout",
+            cls: "line-segment-button-line",
+            height: 3
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.line,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    setSelected: function(v){
+        BI.LineSegmentButton.superclass.setSelected.apply(this, arguments);
+    },
+
+    setText : function(text) {
+        BI.LineSegmentButton.superclass.setText.apply(this, arguments);
+        this.text.setText(text);
+    },
+
+    destroy : function() {
+        BI.LineSegmentButton.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.line_segment_button', BI.LineSegmentButton);/**
+ * 另一套风格的单选按钮组
+ *
+ * Created by GUY on 2015/9/30.
+ * @class BI.LineSegment
+ * @extends BI.Widget
+ */
+BI.LineSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LineSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-line-segment",
+            items: [],
+            height: 30
+        });
+    },
+    _init: function () {
+        BI.LineSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isNumber(o.height)) {
+            this.element.css({height: o.height - 1, lineHeight: (o.height - 1) + 'px'});
+        }
+        this.buttonGroup = BI.createWidget({
+            element: this,
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.line_segment_button",
+                height: o.height - 1
+            }),
+            layout: [
+                {
+                    type: "bi.center"
+                }
+            ]
+        });
+        this.buttonGroup.on(BI.Controller.EVENT_CHANGE, function(){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments)
+        });
+        this.buttonGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.LineSegment.EVENT_CHANGE)
+        })
+    },
+
+    setValue: function (v) {
+        this.buttonGroup.setValue(v);
+    },
+
+    setEnabledValue: function (v) {
+        this.buttonGroup.setEnabledValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.LineSegment.superclass.setEnable.apply(this, arguments);
+        this.buttonGroup.setEnable(v)
+    },
+
+
+    getValue: function () {
+        return this.buttonGroup.getValue();
+    }
+});
+BI.LineSegment.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.line_segment', BI.LineSegment);/**
+ * 拖拽字段的helper
+ * Created by roy on 15/10/13.
+ */
+BI.Helper = BI.inherit(BI.Tip, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Helper.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-helper",
+            text: "",
+            value: ""
+        })
+    },
+
+    _init: function () {
+        BI.Helper.superclass._init.apply(this, arguments);
+        this.populate();
+    },
+
+    modifyContent: function(widget) {
+        this.empty();
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            cls: "dragging-modify",
+            items: [widget],
+            lgap: 15
+        });
+    },
+
+    populate: function () {
+        var o = this.options;
+        this.element.data({helperWidget: this});
+        this.empty();
+        BI.createWidget({
+            element: this,
+            type: "bi.label",
+            textAlign: "center",
+            textHeight: 20,
+            hgap: 5,
+            text: o.text,
+            value: o.value
+        });
+        this.element.removeClass("dragging-modify");
+    }
+});
+$.shortcut("bi.helper", BI.Helper);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBarBar
+ * @extends BI.BasicButton
+ */
+BI.ProgressBarBar = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBarBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar-bar",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBarBar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.svg = BI.createWidget({
+            type: "bi.svg",
+            width: 6,
+            height: 6
+        });
+        this.svg.circle(3, 3, 3).attr({fill: "#ffffff", "stroke": ""});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.svg,
+                right: 10,
+                top: 9
+            }]
+        });
+        this.processor = BI.createWidget({
+            type: "bi.progress_bar_processor",
+            width: "0%",
+            height: o.height
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.processor]
+        });
+    },
+
+    setValue: function (process) {
+        this.processor.setValue(process);
+
+    }
+});
+$.shortcut("bi.progress_bar_bar", BI.ProgressBarBar);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBar
+ * @extends BI.BasicButton
+ */
+BI.ProgressBar = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.bar = BI.createWidget({
+            type: "bi.progress_bar_bar",
+            height: o.height
+        });
+        this.label = BI.createWidget({
+            type: "bi.label",
+            cls: "progress-bar-label",
+            width: 50,
+            height: o.height,
+            value: "0%"
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.bar
+            }, {
+                el: this.label,
+                width: 50
+            }]
+        })
+    },
+
+    setValue: function (process) {
+        if (process >= 100) {
+            process = 100;
+            this.label.element.addClass("success");
+        } else {
+            this.label.element.removeClass("success");
+        }
+        this.label.setValue(process + "%");
+        this.bar.setValue(process);
+    }
+});
+$.shortcut("bi.progress_bar", BI.ProgressBar);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBarProcessor
+ * @extends BI.BasicButton
+ */
+BI.ProgressBarProcessor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBarProcessor.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar-processor",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBarProcessor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.svg = BI.createWidget({
+            type: "bi.svg",
+            width: 12,
+            height: 12
+        });
+        this.svg.circle(6, 6, 6).attr({fill: "#eaeaea", "stroke": ""});
+
+        this.dot = this.svg.circle(6, 6, 3).attr({fill: "#ffffff", "stroke": ""}).hide();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.svg,
+                right: 7,
+                top: 6
+            }]
+        });
+    },
+
+    setValue: function (process) {
+        if (process >= 100) {
+            process = 100;
+            this.dot.show();
+            this.element.addClass("success");
+        } else {
+            this.dot.hide();
+            this.element.removeClass("success");
+        }
+        this.element.width(process + "%");
+    }
+});
+BI.ProgressBarProcessor.EVENT_CHANGE = "ProgressBarProcessor.EVENT_CHANGE";
+$.shortcut("bi.progress_bar_processor", BI.ProgressBarProcessor);/**
+ * 表关联树
+ *
+ * Created by GUY on 2015/12/15.
+ * @class BI.BranchRelation
+ * @extends BI.Widget
+ */
+BI.BranchRelation = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.BranchRelation.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-branch-relation-tree",
+            items: [],
+
+            centerOffset: 0,//重心偏移量
+            direction: BI.Direction.Bottom,
+            align: BI.VerticalAlign.Top
+        })
+    },
+
+    _init: function () {
+        BI.BranchRelation.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    //树分层
+    _stratification: function () {
+        var levels = [];
+        this.tree.recursion(function (node, route) {
+            //node.isRoot = route.length <= 1;
+            node.leaf = node.isLeaf();
+            if (!levels[route.length - 1]) {
+                levels[route.length - 1] = [];
+            }
+            levels[route.length - 1].push(node);
+        });
+        return levels;
+    },
+
+    //计算所有节点的叶子结点个数
+    _calculateLeaves: function () {
+        var count = 0;
+
+        function track(node) {
+            var c = 0;
+            if (node.isLeaf()) {
+                return 1;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                c += track(child);
+            });
+            node.set("leaves", c);
+            return c;
+        }
+
+        count = track(this.tree.getRoot());
+        return count;
+    },
+
+    //树平移
+    _translate: function (levels) {
+        var adjust = [];
+        var maxLevel = levels.length;
+        BI.each(levels, function (i, nodes) {
+            if (!adjust[i]) {
+                adjust[i] = [];
+            }
+            BI.each(nodes, function (j, node) {
+                if (node.isLeaf() && i < maxLevel - 1) {
+                    var newNode = new BI.Node(BI.UUID());
+                    //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot;
+                    newNode.isNew = true;
+                    //把node向下一层移
+                    var tar = 0;
+                    if (j > 0) {
+                        var c = nodes[j - 1].getLastChild();
+                        tar = levels[i + 1].indexOf(c) + 1;
+                    }
+                    levels[i + 1].splice(tar, 0, node);
+                    //新增一个临时树节点
+                    var index = node.parent.getChildIndex(node.id);
+                    node.parent.removeChildByIndex(index);
+                    node.parent.addChild(newNode, index);
+                    newNode.addChild(node);
+                    adjust[i].push(newNode);
+                    nodes[j] = newNode;
+                } else {
+                    adjust[i].push(node);
+                }
+            })
+        });
+        return adjust;
+    },
+
+    //树补白
+    _fill: function (levels) {
+        var adjust = [];
+        var maxLevel = levels.length;
+        BI.each(levels, function (i, nodes) {
+            if (!adjust[i]) {
+                adjust[i] = [];
+            }
+            BI.each(nodes, function (j, node) {
+                if (node.isLeaf() && i < maxLevel - 1) {
+                    var newNode = new BI.Node(BI.UUID());
+                    newNode.leaf = true;
+                    newNode.width = node.width;
+                    newNode.height = node.height;
+                    newNode.isNew = true;
+                    //把node向下一层移
+                    var tar = 0;
+                    if (j > 0) {
+                        var c = nodes[j - 1].getLastChild();
+                        tar = levels[i + 1].indexOf(c) + 1;
+                    }
+                    levels[i + 1].splice(tar, 0, newNode);
+                    //新增一个临时树节点
+                    node.addChild(newNode);
+                }
+                adjust[i].push(node);
+            })
+        });
+        return adjust;
+    },
+
+    //树调整
+    _adjust: function (adjust) {
+        while (true) {
+            var isAllNeedAjust = false;
+            BI.backEach(adjust, function (i, nodes) {
+                BI.each(nodes, function (j, node) {
+                    if (!node.isNew) {
+                        var needAdjust = true;
+                        BI.any(node.getChildren(), function (k, n) {
+                            if (!n.isNew) {
+                                needAdjust = false;
+                                return true;
+                            }
+                        });
+                        if (!node.isLeaf() && needAdjust === true) {
+                            var allChilds = [];
+                            BI.each(node.getChildren(), function (k, n) {
+                                allChilds = allChilds.concat(n.getChildren());
+                            });
+                            node.removeAllChilds();
+                            BI.each(allChilds, function (k, c) {
+                                node.addChild(c);
+                            });
+                            var newNode = new BI.Node(BI.UUID());
+                            //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot;
+                            newNode.isNew = true;
+                            var index = node.parent.getChildIndex(node.id);
+                            node.parent.removeChildByIndex(index);
+                            node.parent.addChild(newNode, index);
+                            newNode.addChild(node);
+                            isAllNeedAjust = true;
+                        }
+                    }
+                })
+            });
+            if (isAllNeedAjust === false) {
+                break;
+            } else {//树重构
+                adjust = this._stratification();
+            }
+        }
+        return adjust;
+    },
+
+    _calculateWidth: function () {
+        var o = this.options;
+        var width = 0;
+
+        function track1(node) {
+            var w = 0;
+            if (node.isLeaf()) {
+                return node.width;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                w += track1(child);
+            });
+            return w;
+        }
+
+        function track2(node) {
+            var w = 0;
+            if (node.isLeaf()) {
+                return node.height;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                w += track2(child);
+            });
+            return w;
+        }
+
+        if (this._isVertical()) {
+            width = track1(this.tree.getRoot());
+        } else {
+            width = track2(this.tree.getRoot());
+        }
+
+        return width;
+    },
+
+    _isVertical: function () {
+        var o = this.options;
+        return o.direction === BI.Direction.Top || o.direction === BI.Direction.Bottom;
+    },
+
+    _calculateHeight: function () {
+        var o = this.options;
+        var height = 0;
+
+        function track1(node) {
+            var h = 0;
+            BI.each(node.getChildren(), function (i, child) {
+                h = Math.max(h, track1(child));
+            });
+            return h + (node.height || 0);
+        }
+
+        function track2(node) {
+            var h = 0;
+            BI.each(node.getChildren(), function (i, child) {
+                h = Math.max(h, track2(child));
+            });
+            return h + (node.width || 0);
+        }
+
+        if (this._isVertical()) {
+            height = track1(this.tree.getRoot());
+        } else {
+            height = track2(this.tree.getRoot());
+        }
+        return height;
+    },
+
+    _calculateXY: function (levels) {
+        var o = this.options;
+        var width = this._calculateWidth();
+        var height = this._calculateHeight();
+        var levelCount = levels.length;
+        var allLeavesCount = this._calculateLeaves();
+        //计算坐标
+        var xy = {};
+        var levelHeight = height / levelCount;
+        BI.each(levels, function (i, nodes) {
+            //计算权重
+            var weights = [];
+            BI.each(nodes, function (j, node) {
+                weights[j] = (node.get("leaves") || 1) / allLeavesCount;
+            });
+            BI.each(nodes, function (j, node) {
+                //求前j个元素的权重
+                var weight = BI.sum(weights.slice(0, j));
+                //求坐标
+                var x = weight * width + weights[j] * width / 2;
+                var y = i * levelHeight + levelHeight / 2;
+                xy[node.id] = {x: x, y: y};
+            })
+        });
+        return xy;
+    },
+
+    _stroke: function (levels, xy) {
+        var height = this._calculateHeight();
+        var levelCount = levels.length;
+        var levelHeight = height / levelCount;
+        var self = this, o = this.options;
+        switch (o.direction) {
+            case BI.Direction.Top:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y + levelHeight / 2;
+                            path += "M" + start.x + "," + (start.y + o.centerOffset) + "L" + start.x + "," + split;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + e.x + "," + (e.y + o.centerOffset) + "L" + e.x + "," + split;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Bottom:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y - levelHeight / 2;
+                            path += "M" + start.x + "," + (start.y - o.centerOffset) + "L" + start.x + "," + split;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + e.x + "," + (e.y - o.centerOffset) + "L" + e.x + "," + split;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Left:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y + levelHeight / 2;
+                            path += "M" + (start.y + o.centerOffset) + "," + start.x + "L" + split + "," + start.x;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + (e.y + o.centerOffset) + "," + e.x + "L" + split + "," + e.x;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Right:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y - levelHeight / 2;
+                            path += "M" + (start.y - o.centerOffset) + "," + start.x + "L" + split + "," + start.x;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + (e.y - o.centerOffset) + "," + e.x + "L" + split + "," + e.x;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+        }
+    },
+
+    _createBranches: function (levels) {
+        var self = this, o = this.options;
+        if (o.direction === BI.Direction.Bottom || o.direction === BI.Direction.Right) {
+            levels = levels.reverse();
+        }
+        var xy = this._calculateXY(levels);
+        //画图
+        this._stroke(levels, xy);
+    },
+
+    _isNeedAdjust: function () {
+        var o = this.options;
+        return o.direction === BI.Direction.Top && o.align === BI.VerticalAlign.Bottom || o.direction === BI.Direction.Bottom && o.align === BI.VerticalAlign.Top
+            || o.direction === BI.Direction.Left && o.align === BI.HorizontalAlign.Right || o.direction === BI.Direction.Right && o.align === BI.HorizontalAlign.Left
+    },
+
+    setValue: function (value) {
+
+    },
+
+    getValue: function () {
+
+    },
+
+    _transformToTreeFormat: function (sNodes) {
+        var i, l;
+        if (!sNodes) {
+            return [];
+        }
+
+        if (BI.isArray(sNodes)) {
+            var r = [];
+            var tmpMap = [];
+            for (i = 0, l = sNodes.length; i < l; i++) {
+                tmpMap[sNodes[i].id] = sNodes[i];
+            }
+            for (i = 0, l = sNodes.length; i < l; i++) {
+                if (tmpMap[sNodes[i].pId] && sNodes[i].id != sNodes[i].pId) {
+                    if (!tmpMap[sNodes[i].pId].children) {
+                        tmpMap[sNodes[i].pId].children = [];
+                    }
+                    tmpMap[sNodes[i].pId].children.push(sNodes[i]);
+                } else {
+                    r.push(sNodes[i]);
+                }
+            }
+            return r;
+        } else {
+            return [sNodes];
+        }
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options;
+        o.items = items || [];
+        this.empty();
+        items = this._transformToTreeFormat(o.items);
+        this.tree = new BI.Tree();
+        this.tree.initTree(items);
+
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+
+        //树分层
+        var levels = this._stratification();
+
+        if (this._isNeedAdjust()) {
+            //树平移
+            var adjust = this._translate(levels);
+            //树调整
+            adjust = this._adjust(adjust);
+
+            this._createBranches(adjust);
+        } else {
+            var adjust = this._fill(levels);
+
+            this._createBranches(adjust);
+        }
+
+        var container = BI.createWidget({
+            type: "bi.layout",
+            width: this._isVertical() ? this._calculateWidth() : this._calculateHeight(),
+            height: this._isVertical() ? this._calculateHeight() : this._calculateWidth()
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container,
+            items: [{
+                el: this.svg,
+                top: 0,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        });
+        if (this._isVertical()) {
+            items = [{
+                type: "bi.handstand_branch_tree",
+                expander: {
+                    direction: o.direction
+                },
+                el: {
+                    layouts: [{
+                        type: "bi.horizontal_adapt",
+                        verticalAlign: o.align
+                    }]
+                },
+                items: items
+            }]
+        } else {
+            items = [{
+                type: "bi.branch_tree",
+                expander: {
+                    direction: o.direction
+                },
+                el: {
+                    layouts: [{
+                        type: "bi.vertical"
+                    }, {
+                        type: o.align === BI.HorizontalAlign.Left ? "bi.left" : "bi.right"
+                    }]
+                },
+                items: items
+            }]
+        }
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: container,
+            items: items
+        });
+        BI.createWidget({
+            type: "bi.center_adapt",
+            scrollable: true,
+            element: this,
+            items: [container]
+        });
+    }
+});
+BI.BranchRelation.EVENT_CHANGE = "BranchRelation.EVENT_CHANGE";
+$.shortcut("bi.branch_relation", BI.BranchRelation);/**
+ * 自定义选色
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.CustomColorChooser
+ * @extends BI.Widget
+ */
+BI.CustomColorChooser = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.CustomColorChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-custom-color-chooser",
+            width: 227,
+            height: 245
+        })
+    },
+
+    _init: function () {
+        BI.CustomColorChooser.superclass._init.apply(this, arguments);
+        var self = this;
+        this.editor = BI.createWidget({
+            type: "bi.color_picker_editor",
+            width: 195
+        });
+        this.editor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+        });
+        this.farbtastic = BI.createWidget({
+            type: "bi.farbtastic"
+        });
+        this.farbtastic.on(BI.Farbtastic.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                type: "bi.absolute",
+                items: [{
+                    el: this.editor,
+                    left: 15,
+                    top: 10,
+                    right: 15
+                }],
+                height: 30
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.farbtastic,
+                    left: 15,
+                    right: 15,
+                    top: 10
+                }],
+                height: 215
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.editor.setValue(color);
+        this.farbtastic.setValue(color);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    }
+});
+BI.CustomColorChooser.EVENT_CHANGE = "CustomColorChooser.EVENT_CHANGE";
+$.shortcut("bi.custom_color_chooser", BI.CustomColorChooser);/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooser
+ * @extends BI.Widget
+ */
+BI.ColorChooser = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-chooser",
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(BI.extend({
+            type: "bi.color_chooser_trigger",
+            width: o.width,
+            height: o.height
+        }, o.el));
+        this.colorPicker = BI.createWidget({
+            type: "bi.color_chooser_popup"
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 1,
+            el: this.trigger,
+            popup: {
+                el: this.colorPicker,
+                stopPropagation: false,
+                minWidth: 202
+            }
+        });
+
+        var fn = function () {
+            var color = self.colorPicker.getValue();
+            self.trigger.setValue(color);
+            var colors = BI.string2Array(BI.Cache.getItem("colors") || "");
+            var que = new BI.Queue(8);
+            que.fromArray(colors);
+            que.remove(color);
+            que.unshift(color);
+            BI.Cache.setItem("colors", BI.array2String(que.toArray()));
+        };
+
+        this.colorPicker.on(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, function () {
+            fn();
+        });
+
+        this.colorPicker.on(BI.ColorChooserPopup.EVENT_CHANGE, function () {
+            fn();
+            self.combo.hideView();
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.colorPicker.setStoreColors(BI.string2Array(BI.Cache.getItem("colors") || ""));
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.fireEvent(BI.ColorChooser.EVENT_CHANGE, arguments);
+        })
+    },
+
+    isViewVisible: function () {
+        return this.combo.isViewVisible();
+    },
+
+    setEnable: function (v) {
+        this.combo.setEnable(v)
+    },
+
+    setValue: function (color) {
+        this.combo.setValue(color);
+    },
+
+    getValue: function () {
+        return this.colorPicker.getValue();
+    }
+});
+BI.ColorChooser.EVENT_CHANGE = "ColorChooser.EVENT_CHANGE";
+$.shortcut("bi.color_chooser", BI.ColorChooser);/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooserPopup
+ * @extends BI.Widget
+ */
+BI.ColorChooserPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorChooserPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-chooser-popup",
+            height: 145
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooserPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.colorEditor = BI.createWidget({
+            type: "bi.color_picker_editor"
+        });
+
+        this.colorEditor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+            self.fireEvent(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, arguments);
+        });
+
+        this.storeColors = BI.createWidget({
+            type: "bi.color_picker",
+            items: [[{
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }]],
+            width: 190,
+            height: 25
+        });
+        this.storeColors.on(BI.ColorPicker.EVENT_CHANGE, function () {
+            self.setValue(this.getValue()[0]);
+            self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+        });
+
+        this.colorPicker = BI.createWidget({
+            type: "bi.color_picker",
+            width: 190,
+            height: 50
+        });
+
+        this.colorPicker.on(BI.ColorPicker.EVENT_CHANGE, function () {
+            self.setValue(this.getValue()[0]);
+            self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+        });
+
+        this.customColorChooser = BI.createWidget({
+            type: "bi.custom_color_chooser"
+        });
+
+        var panel = BI.createWidget({
+            type: "bi.popup_panel",
+            buttons: [BI.i18nText("BI-Basic_Cancel"), BI.i18nText("BI-Basic_Save")],
+            title: BI.i18nText("BI-Custom_Color"),
+            el: this.customColorChooser,
+            stopPropagation: false,
+            bgap: -1,
+            rgap: 1,
+            lgap: 1,
+            minWidth: 227
+        });
+
+        this.more = BI.createWidget({
+            type: "bi.combo",
+            direction: "right,top",
+            isNeedAdjustHeight: false,
+            el: {
+                type: "bi.text_item",
+                cls: "color-chooser-popup-more",
+                textAlign: "center",
+                height: 20,
+                text: BI.i18nText("BI-Basic_More") + "..."
+            },
+            popup: panel
+        });
+
+        this.more.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.customColorChooser.setValue(self.getValue());
+        });
+        panel.on(BI.PopupPanel.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.more.hideView();
+                    break;
+                case 1:
+                    self.setValue(self.customColorChooser.getValue());
+                    self.more.hideView();
+                    self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+                    break;
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    cls: "color-chooser-popup-title",
+                    items: [{
+                        el: this.colorEditor,
+                        left: 0,
+                        right: 0,
+                        top: 5
+                    }]
+                },
+                height: 30
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.storeColors,
+                        left: 5,
+                        right: 5,
+                        top: 5
+                    }]
+                },
+                height: 30
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.colorPicker,
+                        left: 5,
+                        right: 5,
+                        top: 5
+                    }]
+                },
+                height: 65
+            }, {
+                el: this.more,
+                height: 20
+            }]
+        })
+    },
+
+    setStoreColors: function (colors) {
+        if (BI.isArray(colors)) {
+            var items = BI.map(colors, function (i, color) {
+                return {
+                    value: color
+                }
+            });
+            BI.count(colors.length, 8, function (i) {
+                items.push({
+                    value: "",
+                    disabled: true
+                })
+            });
+            this.storeColors.populate([items]);
+        }
+    },
+
+    setValue: function (color) {
+        this.colorEditor.setValue(color);
+        this.colorPicker.setValue(color);
+        this.storeColors.setValue(color);
+    },
+
+    getValue: function () {
+        return this.colorEditor.getValue();
+    }
+});
+BI.ColorChooserPopup.EVENT_VALUE_CHANGE = "ColorChooserPopup.EVENT_VALUE_CHANGE";
+BI.ColorChooserPopup.EVENT_CHANGE = "ColorChooserPopup.EVENT_CHANGE";
+$.shortcut("bi.color_chooser_popup", BI.ColorChooserPopup);/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooserTrigger
+ * @extends BI.Trigger
+ */
+BI.ColorChooserTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        var conf = BI.ColorChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-color-chooser-trigger",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooserTrigger.superclass._init.apply(this, arguments);
+        this.colorContainer = BI.createWidget({
+            type: "bi.layout"
+        });
+
+        var down = BI.createWidget({
+            type: "bi.icon_button",
+            disableSelected: true,
+            cls: "icon-combo-down-icon trigger-triangle-font",
+            width: 12,
+            height: 8
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.colorContainer,
+                left: 3,
+                right: 3,
+                top: 3,
+                bottom: 3
+            }, {
+                el: down,
+                right: 3,
+                bottom: 3
+            }]
+        });
+        if (this.options.value) {
+            this.setValue(this.options.value);
+        }
+    },
+
+    setValue: function (color) {
+        BI.ColorChooserTrigger.superclass.setValue.apply(this, arguments);
+        this.colorContainer.element.css("background-color", color);
+    }
+});
+BI.ColorChooserTrigger.EVENT_CHANGE = "ColorChooserTrigger.EVENT_CHANGE";
+$.shortcut("bi.color_chooser_trigger", BI.ColorChooserTrigger);/**
+ * 新建并选中某个分组按钮
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupAddButton
+ * @extends BI.BasicButton
+ */
+BI.Copy2GroupAddButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.Copy2GroupAddButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + ' bi-copy2group-add-button',
+            shadow: true,
+            isShadowShowingOnSelected: true,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.Copy2GroupAddButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            text: BI.i18nText("BI-Create_And_Select") + "\"江苏\"",
+            height: o.height
+        })
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "move2group-add-font"
+                },
+                width: 30
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    setValue: function (v) {
+        this.text.setValue(BI.i18nText("BI-Create_And_Select") + "\"" + v + "\"");
+        this.setTitle(BI.i18nText("BI-Create_And_Select") + "\"" + v + "\"", {
+            container: "body"
+        });
+    },
+
+    doClick: function () {
+        BI.Copy2GroupAddButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.Copy2GroupAddButton.EVENT_CHANGE);
+        }
+    }
+});
+BI.Copy2GroupAddButton.EVENT_CHANGE = "Copy2GroupAddButton.EVENT_CHANGE";
+$.shortcut('bi.copy2group_add_button', BI.Copy2GroupAddButton);/**
+ * 复制到分组下拉框
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupCombo
+ * @extends BI.Widget
+ */
+BI.Copy2GroupCombo = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Copy2GroupCombo.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-copy2group-combo",
+            height: 30,
+            tipType: "warning",
+            items: []
+        });
+    },
+    _init: function () {
+        BI.Copy2GroupCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.button",
+            text: BI.i18nText("BI-Copy_To_Group"),
+            height: o.height
+        });
+
+        this.tools = BI.createWidget({
+            type: "bi.copy2group_bar"
+        });
+
+        this.tools.on(BI.Copy2GroupBar.EVENT_START, function () {
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_EMPTY, function () {
+            self.combo.adjustHeight();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_CLICK_BUTTON, function () {
+            self.fireEvent(BI.Copy2GroupCombo.EVENT_CLICK_BUTTON);
+            self.searcher.stopSearch();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_CHANGE, function () {
+            this.setButtonVisible(!self.searcher.hasMatched());
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+
+        this.popup = this._createPopup(this.options.items);
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: this.tools,
+            chooseType: BI.Selection.Multi,
+            adapter: this.popup
+        });
+
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+
+        });
+
+        this.multipopup = BI.createWidget({
+            type: "bi.multi_popup_view",
+            width: 200,
+            stopPropagation: false,
+            el: this.popup,
+            tool: this.searcher
+        });
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            isNeedAdjustWidth: false,
+            element: this,
+            el: this.trigger,
+            popup: this.multipopup
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.searcher.stopSearch();
+        });
+
+        this.multipopup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (value) {
+            switch (value) {
+                case 0 :
+                    self.fireEvent(BI.Copy2GroupCombo.EVENT_CONFIRM);
+                    self.combo.hideView();
+                    break;
+                default :
+                    break;
+            }
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            height: 25,
+            handler: function (v) {
+
+            }
+        })
+    },
+
+    _createPopup: function (items, opt) {
+        return BI.createWidget(BI.extend({
+            type: "bi.button_group",
+            items: this._createItems(items),
+            chooseType: 1,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        }, opt));
+    },
+
+
+    scrollToBottom: function () {
+        var self = this;
+        BI.delay(function () {
+            self.popup.element.scrollTop(BI.MAX);
+        }, 30);
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.combo.populate(this._createItems(items));
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+        this.searcher.setValue(v);
+    },
+
+    setEnable: function (enable) {
+        this.combo.setEnable.apply(this.combo, arguments);
+    },
+
+    getTargetValue: function () {
+        return this.tools.getValue();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    }
+});
+BI.Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW = "Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW";
+BI.Copy2GroupCombo.EVENT_CHANGE = "Copy2GroupCombo.EVENT_CHANGE";
+BI.Copy2GroupCombo.EVENT_CONFIRM = "Copy2GroupCombo.EVENT_CONFIRM";
+BI.Copy2GroupCombo.EVENT_CLICK_BUTTON = "Copy2GroupCombo.EVENT_CLICK_BUTTON";
+$.shortcut('bi.copy2group_combo', BI.Copy2GroupCombo);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupBar
+ * @extends BI.Widget
+ */
+BI.Copy2GroupBar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Copy2GroupBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-copy2group-bar"
+        })
+    },
+    _init: function () {
+        BI.Copy2GroupBar.superclass._init.apply(this, arguments);
+        var self = this;
+        this.search = BI.createWidget({
+            type: "bi.text_editor",
+            watermark: BI.i18nText("BI-Search_And_Create_Group"),
+            allowBlank: true
+        });
+
+        this.search.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+
+        this.search.on(BI.TextEditor.EVENT_CHANGE, function () {
+            self.button.setValue(this.getValue());
+            if(this.getValue() !== "") {
+                self.fireEvent(BI.Copy2GroupBar.EVENT_CHANGE);
+            }
+        });
+
+        this.search.on(BI.TextEditor.EVENT_EMPTY, function () {
+            self.button.invisible();
+            self.fireEvent(BI.Copy2GroupBar.EVENT_EMPTY);
+        });
+
+        this.search.on(BI.TextEditor.EVENT_START, function () {
+            self.button.visible();
+            self.fireEvent(BI.Copy2GroupBar.EVENT_START);
+        });
+
+        this.button = BI.createWidget({
+            type: "bi.copy2group_add_button"
+        });
+
+        this.button.on(BI.Copy2GroupAddButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Copy2GroupBar.EVENT_CLICK_BUTTON);
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            vgap: 5,
+            hgap: 5,
+            items: [this.search, this.button]
+        });
+
+        this.button.invisible();
+    },
+
+    blur: function(){
+        this.search.blur();
+    },
+
+    setButtonVisible: function (b) {
+        this.button.setVisible(b);
+    },
+
+    getValue: function () {
+        return this.search.getValue();
+    },
+
+    setValue: function (v) {
+        this.search.setValue(v);
+        this.button.setValue(v);
+    }
+});
+BI.Copy2GroupBar.EVENT_CHANGE = "Copy2GroupBar.EVENT_CHANGE";
+BI.Copy2GroupBar.EVENT_START = "Copy2GroupBar.EVENT_START";
+BI.Copy2GroupBar.EVENT_EMPTY = "Copy2GroupBar.EVENT_EMPTY";
+BI.Copy2GroupBar.EVENT_CLICK_BUTTON = "Copy2GroupBar.EVENT_CLICK_BUTTON";
+$.shortcut("bi.copy2group_bar", BI.Copy2GroupBar);/**
+ * 日期控件中的月份下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.MonthDateCombo
+ * @extends BI.Trigger
+ */
+BI.MonthDateCombo = BI.inherit(BI.Trigger, {
+    _defaultConfig: function() {
+        return BI.extend( BI.MonthDateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-combo",
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.MonthDateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_triangle_trigger"
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.month_popup"
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){
+            self.setValue(self.popup.getValue());
+        })
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            offsetStyle: "center",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        })
+        this.combo.on(BI.Combo.EVENT_CHANGE, function(){
+            self.combo.hideView();
+            self.fireEvent(BI.MonthDateCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function(v){
+        this.trigger.setValue(v + 1);
+        this.popup.setValue(v);
+    },
+
+    getValue: function(){
+        return this.popup.getValue();
+    }
+});
+BI.MonthDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.month_date_combo', BI.MonthDateCombo);/**
+ * 年份下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.YearDateCombo
+ * @extends BI.Trigger
+ */
+BI.YearDateCombo = BI.inherit(BI.Trigger, {
+    _defaultConfig: function() {
+        return BI.extend( BI.YearDateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-combo",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.YearDateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_triangle_trigger"
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.year_popup",
+            min: o.min,
+            max: o.max
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.YearDateCombo.EVENT_CHANGE);
+        })
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            offsetStyle: "center",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        })
+        this.combo.on(BI.Combo.EVENT_CHANGE, function(){
+            self.fireEvent(BI.YearDateCombo.EVENT_CHANGE);
+        })
+    },
+
+    setValue: function(v){
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function(){
+        return this.popup.getValue();
+    }
+});
+BI.YearDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_date_combo', BI.YearDateCombo);/**
+ * Created by GUY on 2015/9/7.
+ * @class BI.DatePicker
+ * @extends BI.Widget
+ */
+BI.DatePicker = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DatePicker.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-picker",
+            height: 25,
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31' //最大日期
+        })
+    },
+
+    _init: function () {
+        BI.DatePicker.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._year = new Date().getFullYear();
+        this._month = new Date().getMonth();
+        this.left = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-h-font",
+            width: 25,
+            height: 25
+        });
+        this.left.on(BI.IconButton.EVENT_CHANGE, function () {
+            if (self._month === 0) {
+                self.setValue({
+                    year: self.year.getValue() - 1,
+                    month: 11
+                })
+            } else {
+                self.setValue({
+                    year: self.year.getValue(),
+                    month: self.month.getValue() - 1
+                })
+            }
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        this.right = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-h-font",
+            width: 25,
+            height: 25
+        });
+
+        this.right.on(BI.IconButton.EVENT_CHANGE, function () {
+            if (self._month === 11) {
+                self.setValue({
+                    year: self.year.getValue() + 1,
+                    month: 0
+                })
+            } else {
+                self.setValue({
+                    year: self.year.getValue(),
+                    month: self.month.getValue() + 1
+                })
+            }
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        this.year = BI.createWidget({
+            type: "bi.year_date_combo",
+            min: o.min,
+            max: o.max
+        });
+        this.year.on(BI.YearDateCombo.EVENT_CHANGE, function () {
+            self.setValue({
+                year: self.year.getValue(),
+                month: self.month.getValue()
+            });
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        })
+        this.month = BI.createWidget({
+            type: "bi.month_date_combo"
+        });
+        this.month.on(BI.MonthDateCombo.EVENT_CHANGE, function () {
+            self.setValue({
+                year: self.year.getValue(),
+                month: self.month.getValue()
+            });
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.left,
+                width: 25
+            }, {
+                type: "bi.center_adapt",
+                items: [{
+                    type: "bi.horizontal",
+                    width: 100,
+                    items: [this.year, this.month]
+                }]
+            }, {
+                el: this.right,
+                width: 25
+            }]
+        })
+        this.setValue({
+            year: this._year,
+            month: this._month
+        })
+    },
+
+    setValue: function (ob) {
+        this._year = ob.year;
+        this._month = ob.month;
+        this.year.setValue(ob.year);
+        this.month.setValue(ob.month);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            month: this.month.getValue()
+        }
+    }
+});
+BI.DatePicker.EVENT_CHANGE = "EVENT_CHANGE"
+$.shortcut("bi.date_picker", BI.DatePicker);/**
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateCalendarPopup
+ * @extends BI.Widget
+ */
+BI.DateCalendarPopup = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DateCalendarPopup.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-calendar-popup",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            selectedTime: null
+        })
+    },
+
+    _createNav: function (v) {
+        var date = BI.Calendar.getDateJSONByPage(v);
+        var calendar = BI.createWidget({
+            type: "bi.calendar",
+            logic: {
+                dynamic: true
+            },
+            min: this.options.min,
+            max: this.options.max,
+            year: date.year,
+            month: date.month,
+            day: this.selectedTime.day
+        });
+        return calendar;
+    },
+
+    _init: function () {
+        BI.DateCalendarPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.today = new Date();
+        this._year = this.today.getFullYear();
+        this._month = this.today.getMonth();
+        this._day = this.today.getDate();
+
+        this.selectedTime = o.selectedTime || {
+                year: this._year,
+                month: this._month,
+                day: this._day
+            };
+        this.datePicker = BI.createWidget({
+            type: "bi.date_picker",
+            min: o.min,
+            max: o.max
+        });
+
+        this.calendar = BI.createWidget({
+            direction: "top",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            type: "bi.navigation",
+            tab: this.datePicker,
+            cardCreator: BI.bind(this._createNav, this),
+
+            afterCardCreated: function () {
+
+            },
+
+            afterCardShow: function () {
+                this.setValue(self.selectedTime);
+            }
+        });
+
+        this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () {
+            self.selectedTime = self.datePicker.getValue();
+            self.selectedTime.day = 1;
+            self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime));
+        });
+
+        this.calendar.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedTime = self.calendar.getValue();
+            self.setValue(self.selectedTime);
+            self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (timeOb) {
+        this.datePicker.setValue(timeOb);
+        this.calendar.setSelect(BI.Calendar.getPageByDateJSON(timeOb));
+        this.calendar.setValue(timeOb);
+        this.selectedTime = timeOb;
+    },
+
+    getValue: function () {
+        return this.selectedTime;
+    }
+});
+BI.DateCalendarPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.date_calendar_popup", BI.DateCalendarPopup);/**
+ * 日期控件中的年份或月份trigger
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateTriangleTrigger
+ * @extends BI.Trigger
+ */
+BI.DateTriangleTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        height: 25,
+        iconWidth: 16,
+        iconHeight: 13
+    },
+
+    _defaultConfig: function() {
+        return BI.extend( BI.DateTriangleTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-triangle-trigger pull-down-ha-font cursor-pointer",
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.DateTriangleTrigger.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "right",
+            text: o.text,
+            value: o.value,
+            height: c.height
+        })
+        this.icon = BI.createWidget({
+            type: "bi.icon",
+            width: c.iconWidth,
+            height: c.iconHeight
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                width: 50,
+                height: c.height,
+                items: [this.text, this.icon]
+            }]
+        })
+    },
+
+    setValue: function(v){
+        this.text.setValue(v);
+    },
+
+    getValue: function(){
+        return this.text.getValue();
+    },
+
+    setText: function(v){
+        this.text.setText(v);
+    },
+
+    getText: function(){
+        return this.item.getText();
+    },
+
+    getKey: function(){
+
+    }
+});
+$.shortcut('bi.date_triangle_trigger', BI.DateTriangleTrigger);/**
+ * 日期下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateCombo
+ * @extends BI.Widget
+ */
+BI.DateCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-combo",
+            height: 30
+        });
+    },
+    _init: function () {
+        BI.DateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_trigger"
+        });
+
+        this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function () {
+            self.combo.toggle();
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.date_calendar_popup"
+        });
+
+        this.popup.on(BI.DateCalendarPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                width: 270,
+                el: this.popup,
+                stopPropagation: false
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+$.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 30,
+        watermark: BI.i18nText("BI-Unrestricted"),
+        yearLength: 4,
+        yearMonthLength: 7
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-date-trigger",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.DateTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                var date = v.match(/\d+/g);
+                self._autoAppend(v, date);
+                return self._dateCheck(v) && Date.checkLegal(v) && self._checkVoid({
+                        year: date[0],
+                        month: date[1],
+                        day: date[2]
+                    });
+            },
+            quitChecker: function () {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            watermark: c.watermark,
+            errorText: function () {
+                if (self.editor.isEditing()) {
+                    return BI.i18nText("BI-Date_Trigger_Error_Text");
+                }
+                return BI.i18nText("BI-Year_Trigger_Invalid_Text");
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_KEY_DOWN)
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setState(value);
+            }
+
+            if (BI.isNotEmptyString(value)) {
+                var date = value.split("-");
+                self.store_value = {
+                    type: BICst.MULTI_DATE_CALENDAR,
+                    value:{
+                        year: date[0] | 0,
+                        month: date[1] - 1,
+                        day: date[2] | 0
+                    }
+                };
+            }
+            self.fireEvent(BI.DateTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_CHANGE);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: BI.createWidget(),
+                width: 30
+            }, {
+                el: this.editor
+            }]
+        })
+    },
+    _dateCheck: function (date) {
+        return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date;
+    },
+    _checkVoid: function (obj) {
+        return !Date.checkVoid(obj.year, obj.month, obj.day, this.options.min, this.options.max)[0];
+    },
+    _autoAppend: function (v, dateObj) {
+        var self = this;
+        var date = Date.parseDateTime(v, "%Y-%X-%d").print("%Y-%X-%d");
+        var yearCheck = function (v) {
+            return Date.parseDateTime(v, "%Y").print("%Y") == v && date >= self.options.min && date <= self.options.max;
+        };
+        var monthCheck = function (v) {
+            return Date.parseDateTime(v, "%Y-%X").print("%Y-%X") == v && date >= self.options.min && date <= self.options.max;
+        };
+        if (BI.isNotNull(dateObj) && Date.checkLegal(v)) {
+            switch (v.length) {
+                case this._const.yearLength:
+                    if (yearCheck(v)) {
+                        this.editor.setValue(v + "-");
+                    }
+                    break;
+                case this._const.yearMonthLength:
+                    if (monthCheck(v)) {
+                        this.editor.setValue(v + "-");
+                    }
+                    break;
+            }
+        }
+    },
+
+    setValue: function (v) {
+        var type, value, self = this;
+        var date = new Date();
+        this.store_value = v;
+        if (BI.isNotNull(v)) {
+            type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value;
+            if(BI.isNull(value)){
+                value = v;
+            }
+        }
+        var _setInnerValue = function (date, text) {
+            var dateStr = date.print("%Y-%x-%e");
+            self.editor.setState(dateStr);
+            self.editor.setValue(dateStr);
+            self.setTitle(text + ":" + dateStr);
+        };
+        switch (type) {
+            case BICst.MULTI_DATE_YEAR_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV];
+                date = new Date((date.getFullYear() - 1 * value), date.getMonth(), date.getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER];
+                date = new Date((date.getFullYear() + 1 * value), date.getMonth(), date.getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN];
+                date = new Date(date.getFullYear(), 0, 1);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END];
+                date = new Date(date.getFullYear(), 11, 31);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV];
+                date = new Date().getBeforeMulQuarter(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER];
+                date = new Date().getAfterMulQuarter(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN];
+                date = new Date().getQuarterStartDate();
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END];
+                date = new Date().getQuarterEndDate();
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV];
+                date = new Date().getBeforeMultiMonth(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER];
+                date = new Date().getAfterMultiMonth(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN];
+                date = new Date(date.getFullYear(), date.getMonth(), 1);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END];
+                date = new Date(date.getFullYear(), date.getMonth(), (date.getLastDateOfMonth()).getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_WEEK_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV];
+                date = date.getOffsetDate(-7 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_WEEK_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER];
+                date = date.getOffsetDate(7 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV];
+                date = date.getOffsetDate(-1 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER];
+                date = date.getOffsetDate(1 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_TODAY:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY];
+                date = new Date();
+                _setInnerValue(date, text);
+                break;
+            default:
+                if (BI.isNull(value) || BI.isNull(value.day)) {
+                    this.editor.setState("");
+                    this.editor.setValue("");
+                    this.setTitle("");
+                } else {
+                    var dateStr = value.year + "-" + (value.month + 1) + "-" + value.day;
+                    this.editor.setState(dateStr);
+                    this.editor.setValue(dateStr);
+                    this.setTitle(dateStr);
+                }
+                break;
+        }
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+    getValue: function () {
+        return this.store_value;
+    }
+
+});
+BI.DateTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.DateTrigger.EVENT_START = "EVENT_START";
+BI.DateTrigger.EVENT_STOP = "EVENT_STOP";
+BI.DateTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.DateTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DateTrigger.EVENT_VALID = "EVENT_VALID";
+BI.DateTrigger.EVENT_ERROR = "EVENT_ERROR";
+BI.DateTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK";
+BI.DateTrigger.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+$.shortcut("bi.date_trigger", BI.DateTrigger);/**
+ * Created by zcf on 2017/2/20.
+ */
+BI.DatePaneWidget = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DatePaneWidget.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-pane-widget",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            selectedTime: null
+        })
+    },
+    _init: function () {
+        BI.DatePaneWidget.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.today = new Date();
+        this._year = this.today.getFullYear();
+        this._month = this.today.getMonth();
+
+        this.selectedTime = o.selectedTime || {
+                year: this._year,
+                month: this._month
+            };
+
+        this.datePicker = BI.createWidget({
+            type: "bi.date_picker",
+            min: o.min,
+            max: o.max
+        });
+        this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () {
+            self.selectedTime = self.datePicker.getValue();
+            // self.selectedTime.day = 1;
+            self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime));
+        });
+
+        this.calendar = BI.createWidget({
+            direction: "top",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            type: "bi.navigation",
+            tab: this.datePicker,
+            cardCreator: BI.bind(this._createNav, this)
+
+            // afterCardCreated: function () {
+            //
+            // },
+            //
+            // afterCardShow: function () {
+            //     // this.setValue(self.selectedTime);
+            // }
+        });
+        this.calendar.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedTime = self.calendar.getValue();
+            self.calendar.empty();
+            self.setValue(self.selectedTime);
+            self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE);
+        });
+
+    },
+
+    _createNav: function (v) {
+        var date = BI.Calendar.getDateJSONByPage(v);
+        var calendar = BI.createWidget({
+            type: "bi.calendar",
+            logic: {
+                dynamic: true
+            },
+            min: this.options.min,
+            max: this.options.max,
+            year: date.year,
+            month: date.month,
+            day: this.selectedTime.day
+        });
+        return calendar;
+    },
+
+    _getNewCurrentDate: function () {
+        var today = new Date();
+        return {
+            year: today.getFullYear(),
+            month: today.getMonth()
+        }
+    },
+
+    _setCalenderValue: function (date) {
+        this.calendar.setSelect(BI.Calendar.getPageByDateJSON(date));
+        this.calendar.setValue(date);
+        this.selectedTime = date;
+    },
+
+    _setDatePicker: function (timeOb) {
+        if (BI.isNull(timeOb) || BI.isNull(timeOb.year) || BI.isNull(timeOb.month)) {
+            this.datePicker.setValue(this._getNewCurrentDate());
+        } else {
+            this.datePicker.setValue(timeOb);
+        }
+    },
+
+    _setCalendar: function (timeOb) {
+        if (BI.isNull(timeOb) || BI.isNull(timeOb.day)) {
+            this.calendar.empty();
+            this._setCalenderValue(this._getNewCurrentDate());
+        } else {
+            this._setCalenderValue(timeOb)
+        }
+    },
+
+    setValue: function (timeOb) {
+        this._setDatePicker(timeOb);
+        this._setCalendar(timeOb);
+    },
+
+    getValue: function () {
+        return this.selectedTime;
+    }
+
+});
+$.shortcut("bi.date_pane_widget", BI.DatePaneWidget);/**
+ * 带有方向的pathchooser
+ *
+ * Created by GUY on 2016/4/21.
+ * @class BI.DirectionPathChooser
+ * @extends BI.Widget
+ */
+BI.DirectionPathChooser = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#808080",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DirectionPathChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.DirectionPathChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.pathChooser = BI.createWidget({
+            type: "bi.path_chooser",
+            element: this,
+            items: o.items
+        });
+        this.pathChooser.on(BI.PathChooser.EVENT_CHANGE, function (start, index) {
+            //self._unselectAllArrows();
+            self._setValue(start, index);
+            self.fireEvent(BI.DirectionPathChooser.EVENT_CHANGE);
+        });
+        this._drawArrows();
+
+    },
+
+    _unselectAllArrows: function () {
+        var self = this, lineColor = this._const.lineColor;
+        BI.each(this.arrows, function (region, rs) {
+            BI.each(rs, function (idx, arrows) {
+                BI.each(arrows, function (i, arrow) {
+                    arrow.attr({fill: lineColor, stroke: lineColor});
+                });
+            });
+        });
+    },
+
+    _drawOneArrow: function (dot, direction) {
+        //0,1,2,3  上右下左
+        var lineColor = this._const.lineColor;
+        var selectLineColor = this._const.selectLineColor;
+        var svg = this.pathChooser.svg;
+        var path = "";
+        switch (direction) {
+            case 0:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 3) + "," + (dot.y + 5)
+                    + "L" + (dot.x + 3) + "," + (dot.y + 5)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 1:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 5) + "," + (dot.y - 3)
+                    + "L" + (dot.x - 5) + "," + (dot.y + 3)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 2:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 3) + "," + (dot.y - 5)
+                    + "L" + (dot.x + 3) + "," + (dot.y - 5)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 3:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x + 5) + "," + (dot.y - 3)
+                    + "L" + (dot.x + 5) + "," + (dot.y + 3)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+        }
+        return svg.path(path).attr({fill: lineColor, stroke: lineColor});
+    },
+
+    _drawArrows: function () {
+        var self = this, o = this.options;
+        var routes = this.pathChooser.routes;
+        var pathes = this.pathChooser.pathes;
+        var store = this.pathChooser.store;
+        this.arrows = {};
+        BI.each(routes, function (region, ps) {
+            self.arrows[region] = [];
+            BI.each(ps, function (idx, path) {
+                self.arrows[region][idx] = [];
+                var dots = pathes[region][idx];
+                BI.each(dots, function (i, dot) {
+                    if (i > 0 && i < dots.length - 1) {
+                        var arrow;
+                        if (dot.y === dots[i - 1].y) {
+                            if (dots[i + 1].y != dot.y) {
+                                if (store[path[path.length - 2]].direction === -1) {
+                                    if (i - 1 > 0) {
+                                        arrow = self._drawOneArrow(dots[i - 1], 3);
+                                    }
+                                } else {
+                                    arrow = self._drawOneArrow(dots[i], 1);
+                                }
+                            }
+                        } else if (dot.x === dots[i - 1].x) {
+                            if (dot.y > dots[i - 1].y) {
+                                if (store[BI.first(path)].direction === -1) {
+                                    arrow = self._drawOneArrow(dots[i - 1], 0);
+                                } else {
+                                    arrow = self._drawOneArrow(dot, 2);
+                                }
+                            } else {
+                                if (store[path[path.length - 2]].direction === -1) {
+                                    arrow = self._drawOneArrow(dots[i - 1], 2);
+                                } else {
+                                    arrow = self._drawOneArrow(dot, 0);
+                                }
+                            }
+                        }
+                        if (arrow) {
+                            self.arrows[region][idx].push(arrow);
+                        }
+                    }
+                });
+                BI.each(path, function (i, node) {
+                    if (i !== 0) {
+                        var arrow;
+                        var from = path[i - 1];
+                        if (store[from].direction === -1) {
+                            var regionIndex = self.pathChooser.getRegionIndexById(from);
+                            var x = getXoffsetByRegionIndex(regionIndex, -1);
+                            var y = getYByXoffset(dots, x);
+                            arrow = self._drawOneArrow({x: x, y: y}, 3);
+                        } else {
+                            var regionIndex = self.pathChooser.getRegionIndexById(node);
+                            var x = getXoffsetByRegionIndex(regionIndex);
+                            var y = getYByXoffset(dots, x);
+                            arrow = self._drawOneArrow({x: x, y: y}, 1);
+                        }
+                        if (arrow) {
+                            self.arrows[region][idx].push(arrow);
+                        }
+                    }
+                });
+            })
+        });
+
+        function getXoffsetByRegionIndex(regionIndex, diregion) {
+            if (diregion === -1) {
+                return 100 * (regionIndex + 1) - 20;
+            }
+            return 100 * regionIndex + 20;
+        }
+
+        function getYByXoffset(dots, xoffset) {
+            var finded = BI.find(dots, function (i, dot) {
+                if (i > 0) {
+                    if (dots[i - 1].x < xoffset && dots[i].x > xoffset) {
+                        return true;
+                    }
+                }
+            });
+            return finded.y;
+        }
+    },
+
+    _setValue: function (start, index) {
+        var self = this;
+        var lineColor = this._const.lineColor;
+        var selectLineColor = this._const.selectLineColor;
+        var routes = this.pathChooser.routes;
+        var starts = this.pathChooser.start;
+        var each = [start];
+        if (starts.contains(start)) {
+            each = starts;
+        }
+        BI.each(each, function (i, s) {
+            BI.each(self.arrows[s], function (j, arrows) {
+                BI.each(arrows, function (k, arrow) {
+                    arrow.attr({fill: lineColor, stroke: lineColor}).toFront();
+                });
+            });
+        });
+        BI.each(this.arrows[start][index], function (i, arrow) {
+            arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront();
+        });
+        var current = BI.last(routes[start][index]);
+        while (current && routes[current] && routes[current].length === 1) {
+            BI.each(self.arrows[current][0], function (i, arrow) {
+                arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront();
+            });
+            current = BI.last(routes[current][0]);
+        }
+    },
+
+    setValue: function (v) {
+        this.pathChooser.setValue(v);
+        this._unselectAllArrows();
+        var routes = this.pathChooser.routes;
+        var nodes = BI.keys(routes), self = this;
+        var result = [], array = [];
+        BI.each(v, function (i, val) {
+            if (BI.contains(nodes, val)) {
+                if (array.length > 0) {
+                    array.push(val);
+                    result.push(array);
+                    array = [];
+                }
+            }
+            array.push(val);
+        });
+        if (array.length > 0) {
+            result.push(array);
+        }
+        //画这n条路径
+        BI.each(result, function (idx, path) {
+            var start = path[0];
+            var index = BI.findIndex(routes[start], function (idx, p) {
+                if (BI.isEqual(path, p)) {
+                    return true;
+                }
+            });
+            if (index >= 0) {
+                self._setValue(start, index);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.pathChooser.getValue();
+    },
+
+    populate: function (items) {
+        this.pathChooser.populate(items);
+        this._drawArrows();
+    }
+});
+BI.DirectionPathChooser.EVENT_CHANGE = "DirectionPathChooser.EVENT_CHANGE";
+$.shortcut('bi.direction_path_chooser', BI.DirectionPathChooser);/**
+ * Created by roy on 15/8/14.
+ */
+BI.DownListCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-combo",
+            invalid: false,
+            height: 25,
+            items: [],
+            adjustLength: 0,
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.DownListCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.popupview = BI.createWidget({
+            type: "bi.down_list_popup",
+            items: o.items,
+            chooseType: o.chooseType
+        });
+
+        this.popupview.on(BI.DownListPopup.EVENT_CHANGE, function (value) {
+            self.fireEvent(BI.DownListCombo.EVENT_CHANGE, value);
+            self.downlistcombo.hideView();
+        });
+
+        this.popupview.on(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, function (value, fatherValue) {
+            self.fireEvent(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, value, fatherValue);
+            self.downlistcombo.hideView();
+        });
+
+
+        this.downlistcombo = BI.createWidget({
+            element: this,
+            type: 'bi.combo',
+            isNeedAdjustWidth: false,
+            adjustLength: o.adjustLength,
+            el: BI.createWidget(o.el, {
+                type: "bi.icon_trigger",
+                extraCls: o.iconCls ? o.iconCls : "pull-down-font",
+                width: o.width,
+                height: o.height
+            }),
+            popup: {
+                el: this.popupview,
+                stopPropagation: true,
+                maxHeight: 400
+            }
+        });
+
+        this.downlistcombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.DownListCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+    },
+
+    populate: function (items) {
+        this.popupview.populate(items);
+    },
+
+    setValue: function (v) {
+        this.popupview.setValue(v);
+    },
+    getValue: function () {
+        return this.popupview.getValue()
+    }
+});
+BI.DownListCombo.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DownListCombo.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE";
+BI.DownListCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+
+$.shortcut("bi.down_list_combo", BI.DownListCombo);/**
+ * Created by roy on 15/9/6.
+ */
+BI.DownListGroup = BI.inherit(BI.Widget, {
+    constants: {
+        iconCls: "check-mark-ha-font"
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-group",
+            items: [
+                {
+                    el: {}
+                }
+            ]
+        })
+    },
+    _init: function () {
+        BI.DownListGroup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+
+        this.downlistgroup = BI.createWidget({
+            element: this,
+            type: "bi.button_tree",
+            items: o.items,
+            chooseType: 0,//0单选,1多选
+            layouts: [{
+                type: "bi.vertical",
+                hgap: 0,
+                vgap: 0
+            }]
+        });
+        this.downlistgroup.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if(type === BI.Events.CLICK) {
+                self.fireEvent(BI.DownListGroup.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+    getValue:function(){
+        return this.downlistgroup.getValue();
+    },
+    setValue:function(v){
+        this.downlistgroup.setValue(v);
+    }
+
+
+})
+BI.DownListGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_group", BI.DownListGroup);BI.DownListItem = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.DownListItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-down-list-item",
+            cls: "",
+            height: 25,
+            logic: {
+                dynamic: true
+            },
+            selected: false,
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.DownListItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.icon_text_item",
+            element: this,
+            height: o.height,
+            text: o.text,
+            value: o.value,
+            logic: o.logic,
+            selected: o.selected,
+            disabled: o.disabled,
+            iconHeight: o.iconHeight,
+            iconWidth: o.iconWidth,
+            textHgap: o.textHgap,
+            textVgap: o.textVgap,
+            textLgap: o.textLgap,
+            textRgap: o.textRgap,
+            father: o.father
+        });
+        this.text.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.text.on(BI.IconTextItem.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DownListItem.EVENT_CHANGE);
+        });
+        // this.setSelected(o.selected);
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    isSelected: function () {
+        return this.text.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.text.setSelected(b);
+        // if (b === true) {
+        //     this.element.addClass("dot-e-font");
+        // } else {
+        //     this.element.removeClass("dot-e-font");
+        // }
+    },
+
+    setValue: function (v) {
+        this.text.setValue(v);
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    }
+});
+BI.DownListItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_item", BI.DownListItem);BI.DownListGroupItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        var conf = BI.DownListGroupItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-down-list-group-item",
+            logic: {
+                dynamic: false
+            },
+            invalid: true,
+            iconCls1: "dot-e-font",
+            iconCls2: "pull-right-e-font"
+        })
+    },
+    _init: function () {
+        BI.DownListGroupItem.superclass._init.apply(this, arguments);
+        var o = this.options;
+        var self = this;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-group-item-text",
+            textAlign: "left",
+            text: o.text,
+            value: o.value,
+            height: o.height
+        })
+
+        this.icon1 = BI.createWidget({
+            type: "bi.icon_button",
+            cls: o.iconCls1,
+            width: 25,
+            forceNotSelected: true
+        })
+
+        this.icon2 = BI.createWidget({
+            type: "bi.icon_button",
+            cls: o.iconCls2,
+            width: 25,
+            forceNotSelected: true
+        })
+
+        var blank = BI.createWidget({
+            type: "bi.layout",
+            width: 25
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.icon2,
+                top: 0,
+                bottom: 0,
+                right: 0
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon1, this.text, blank)
+        }))));
+
+        this.element.on("mouseenter." + this.getName(), function (e) {
+            if (self.element.__isMouseInBounds__(e) && self.isEnabled()) {
+                self.hover();
+            } else {
+                self.dishover();
+            }
+        });
+        this.element.on("mousemove." + this.getName(), function (e) {
+            if (!self.element.__isMouseInBounds__(e) && self.isEnabled()) {
+                self.dishover()
+            }
+        });
+        this.element.on("mouseleave." + this.getName(), function () {
+            if (self.isEnabled()) {
+                self.dishover()
+            }
+        });
+    },
+
+    hover: function () {
+        BI.DownListGroupItem.superclass.hover.apply(this, arguments);
+        this.icon1.element.addClass("hover");
+        this.icon2.element.addClass("hover");
+
+    },
+
+    dishover: function () {
+        BI.DownListGroupItem.superclass.dishover.apply(this, arguments);
+        this.icon1.element.removeClass("hover");
+        this.icon2.element.removeClass("hover");
+    },
+
+    doClick: function () {
+        BI.DownListGroupItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.DownListGroupItem.EVENT_CHANGE, this.getValue());
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    setValue: function (v) {
+        var self = this, o = this.options;
+        v = BI.isArray(v) ? v : [v];
+        BI.find(v, function(idx, value){
+            if(BI.contains(o.childValues, value)){
+                self.icon1.setSelected(true);
+                return true;
+            }else{
+                self.icon1.setSelected(false);
+            }
+        })
+    }
+});
+BI.DownListGroupItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_group_item", BI.DownListGroupItem);/**
+ * Created by roy on 15/9/8.
+ * 处理popup中的item分组样式
+ * 一个item分组中的成员大于一时,该分组设置为单选,并且默认状态第一个成员设置为已选择项
+ */
+BI.DownListPopup = BI.inherit(BI.Pane, {
+    constants: {
+        nextIcon: "pull-right-e-font",
+        height: 25,
+        iconHeight: 12,
+        iconWidth: 12,
+        hgap: 0,
+        vgap: 0,
+        border: 1
+    },
+    _defaultConfig: function () {
+        var conf = BI.DownListPopup.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-down-list-popup",
+            items: [],
+            chooseType: BI.Selection.Multi
+        })
+    },
+    _init: function () {
+        BI.DownListPopup.superclass._init.apply(this, arguments);
+        this.singleValues = [];
+        this.childValueMap = {};
+        this.fatherValueMap = {};
+        var self = this, o = this.options, children = this._createChildren(o.items);
+        this.popup = BI.createWidget({
+            type: "bi.button_tree",
+            items: BI.createItems(children,
+                {}, {
+                    adjustLength: -2
+                }
+            ),
+            layouts: [{
+                type: "bi.vertical",
+                hgap: this.constants.hgap,
+                vgap: this.constants.vgap
+            }],
+            chooseType: o.chooseType
+        });
+
+        this.popup.on(BI.ButtonTree.EVENT_CHANGE, function (value, object) {
+            var changedValue = value;
+            if (BI.isNotNull(self.childValueMap[value])) {
+                changedValue = self.childValueMap[value];
+                self.fireEvent(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, changedValue, self.fatherValueMap[value])
+            } else {
+                self.fireEvent(BI.DownListPopup.EVENT_CHANGE, changedValue, object);
+            }
+
+
+            if (!self.singleValues.contains(changedValue)) {
+                var item = self.getValue();
+                var result = [];
+                BI.each(item, function (i, valueObject) {
+                    if (valueObject.value != changedValue) {
+                        result.push(valueObject);
+                    }
+                });
+                self.setValue(result);
+            }
+
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+
+    },
+    _createChildren: function (items) {
+        var self = this, result = [];
+        BI.each(items, function (i, it) {
+            var item_done = {
+                type: "bi.down_list_group",
+                items: []
+            };
+
+            BI.each(it, function (i, item) {
+                if (BI.isNotEmptyArray(item.children) && !BI.isEmpty(item.el)) {
+                    item.type = "bi.combo_group";
+                    item.cls = "down-list-group";
+                    item.trigger = "hover";
+                    item.isNeedAdjustWidth = false;
+                    item.el.title = item.el.title || item.el.text;
+                    item.el.type = "bi.down_list_group_item";
+                    item.el.logic = {
+                        dynamic: true
+                    };
+                    item.el.height = self.constants.height;
+                    item.el.iconCls2 = self.constants.nextIcon;
+                    item.popup = {
+                        lgap: 4,
+                        el: {
+                            type: "bi.button_tree",
+                            chooseType: 0,
+                            layouts: [{
+                                type: "bi.vertical"
+                            }]
+
+                        }
+                    };
+                    item.el.childValues = [];
+                    BI.each(item.children, function (i, child) {
+                        var fatherValue = BI.deepClone(item.el.value);
+                        var childValue = BI.deepClone(child.value);
+                        self.singleValues.push(child.value);
+                        child.type = "bi.down_list_item";
+                        child.extraCls = " child-down-list-item";
+                        child.title = child.title || child.text;
+                        child.textRgap = 10;
+                        child.isNeedAdjustWidth = false;
+                        child.logic = {
+                            dynamic: true
+                        };
+                        child.father = fatherValue;
+                        self.fatherValueMap[self._createChildValue(fatherValue, childValue)] = fatherValue;
+                        self.childValueMap[self._createChildValue(fatherValue, childValue)] = childValue;
+                        child.value = self._createChildValue(fatherValue, childValue);
+                        item.el.childValues.push(child.value);
+                    })
+                } else {
+                    item.type = "bi.down_list_item";
+                    item.title = item.title || item.text;
+                    item.textRgap = 10;
+                    item.isNeedAdjustWidth = false;
+                    item.logic = {
+                        dynamic: true
+                    }
+                }
+                var el_done = {};
+                el_done.el = item;
+                item_done.items.push(el_done);
+            });
+            if (self._isGroup(item_done.items)) {
+                BI.each(item_done.items, function (i, item) {
+                    self.singleValues.push(item.el.value);
+                })
+            }
+
+            result.push(item_done);
+            if (self._needSpliter(i, items.length)) {
+                var spliter_container = BI.createWidget({
+                    type: "bi.vertical",
+                    items: [{
+                        el: {
+                            type: "bi.layout",
+                            cls: "bi-down-list-spliter cursor-pointer",
+                            height: 0
+                        }
+
+                    }],
+                    cls: "bi-down-list-spliter-container cursor-pointer",
+                    lgap: 10,
+                    rgap: 10
+                });
+                result.push(spliter_container);
+            }
+        });
+        return result;
+    },
+
+    _isGroup: function (i) {
+        return i.length > 1;
+    },
+
+    _needSpliter: function (i, itemLength) {
+        return i < itemLength - 1;
+    },
+
+    _createChildValue: function (fatherValue, childValue) {
+        return fatherValue + "_" + childValue
+    },
+
+    populate: function (items) {
+        BI.DownListPopup.superclass.populate.apply(this, arguments);
+        var self = this;
+        self.childValueMap = {};
+        self.fatherValueMap = {};
+        self.singleValues = [];
+        var children = self._createChildren(items);
+        var popupItem = BI.createItems(children,
+            {}, {
+                adjustLength: -2
+            }
+        );
+        self.popup.populate(popupItem);
+    },
+
+    setValue: function (valueItem) {
+        var self = this;
+        var valueArray = [];
+        BI.each(valueItem, function (i, item) {
+                var value;
+                if (BI.isNotNull(item.childValue)) {
+                    value = self._createChildValue(item.value, item.childValue);
+                } else {
+                    value = item.value;
+                }
+                valueArray.push(value);
+            }
+        );
+        this.popup.setValue(valueArray);
+    },
+
+    getValue: function () {
+        var self = this, result = [];
+        var values = this.popup.getValue();
+        BI.each(values, function (i, value) {
+            var valueItem = {};
+            if (BI.isNotNull(self.childValueMap[value])) {
+                var fartherValue = self.fatherValueMap[value];
+                valueItem.childValue = self.childValueMap[value];
+                valueItem.value = fartherValue;
+            } else {
+                valueItem.value = value;
+            }
+            result.push(valueItem);
+        });
+        return result;
+    }
+
+
+});
+
+BI.DownListPopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DownListPopup.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE";
+$.shortcut("bi.down_list_popup", BI.DownListPopup);/**
+ * Created by windy on 2016/12/20.
+ */
+BI.DynamicGroupTabButtonGroup = BI.inherit(BI.Widget, {
+
+    _const: {
+        MERGE_ADD_WIDTH: 65
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DynamicGroupTabButtonGroup.superclass._defaultConfig.apply(this, arguments), {
+            cls: "bi-dynamic-group-tab-button-group",
+            items: [],
+            frozenButtons: [],
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DynamicGroupTabButtonGroup.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.tab = BI.createWidget({
+            type: "bi.button_group",
+            height: o.height,
+            items: [],
+            layouts: [{
+                type: "bi.horizontal",
+                scrollable: false,
+                scrollx: false
+            }]
+        });
+
+        this.tab.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.DynamicGroupTabButtonGroup.EVENT_CHANGE, arguments);
+        });
+
+        var self = this;
+
+        this.scrollLeft = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-font bi-icon-button-scroll",
+            invisible: true
+        });
+
+        this.scrollLeft.on(BI.IconButton.EVENT_CHANGE, function () {
+            self._scrollLeft();
+        });
+        this.scrollRight = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-font bi-icon-button-scroll",
+            invisible: true
+        });
+        this.scrollRight.on(BI.IconButton.EVENT_CHANGE, function () {
+            self._scrollRight();
+        });
+        BI.ResizeDetector.addResizeListener(this, function () {
+            self.resize();
+        });
+
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [{
+                type: "bi.horizontal",
+                tgap: -1,
+                height: o.height,
+                scrollx: false,
+                cls: "bi-sheet-tab-dynamic-horizontal",
+                items: [this.tab,
+                    {
+                        type: "bi.vertical_adapt",
+                        items: [this.scrollLeft],
+                        height: o.height
+                    },
+                    {
+                        type: "bi.vertical_adapt",
+                        items: [this.scrollRight],
+                        height: o.height
+                    },
+                    {
+                        type: "bi.vertical_adapt",
+                        items: o.frozenButtons,
+                        height: o.height,
+                        lgap: 10
+                    }
+                ]
+            }]
+        })
+    },
+
+    _scrollLeft: function () {
+        this._scrollTo(this.tab.element[0].scrollLeft - this.scrollSection)
+    },
+
+    _scrollRight: function () {
+        this._scrollTo(this.tab.element[0].scrollLeft + this.scrollSection)
+    },
+
+    _getTotalWidth: function () {
+        var totalWidth = this.element.outerWidth();
+        totalWidth -= this._const.MERGE_ADD_WIDTH;
+        BI.each(this.options.frozenButtons, function (idx, button) {
+            if (BI.isWidget(button)) {
+                totalWidth -= button.getWidth();
+            } else {
+                totalWidth -= button.width;
+            }
+        })
+        return totalWidth;
+    },
+
+    _calculateButtonsWith: function (fn) {
+        var buttonWidth = 0;
+        var self = this;
+        BI.some(this.tab.getAllButtons(), function (idx, item) {
+            buttonWidth += item.element.outerWidth();
+            if (BI.isNotNull(fn) && fn.apply(self, [item])) {
+                return true;
+            }
+        })
+        return buttonWidth;
+    },
+
+    _dealWithScrollButtonState: function () {
+        var buttonWidth = this._calculateButtonsWith();
+        if (this.tab.element[0].scrollLeft === 0) {
+            this.scrollLeft.setEnable(false);
+        } else {
+            this.scrollLeft.setEnable(true);
+        }
+        var ulWidth = this.tab.element.outerWidth();
+        //可以滚动的最大距离
+        var maxLeft = buttonWidth - ulWidth;
+        if (this.tab.element[0].scrollLeft === maxLeft) {
+            this.scrollRight.setEnable(false);
+        } else {
+            this.scrollRight.setEnable(true);
+        }
+    },
+
+    _needScroll: function (visibleWidth, buttonWidth) {
+        var currentLeft = this.tab.element[0].scrollLeft;
+        return (visibleWidth > currentLeft && visibleWidth - currentLeft > buttonWidth) ||
+            (visibleWidth < currentLeft)
+    },
+
+    _scrollTo: function (value) {
+        var self = this;
+        BI.delay(function () {
+            self.tab.element.scrollLeft(value);
+            self._dealWithScrollButtonState();
+        }, 30);
+    },
+
+    _scrollToEnd: function () {
+        this._scrollTo(this._calculateButtonsWith())
+    },
+
+    resize: function () {
+        //获取当前所有可使用的宽度,不包含添加和合并和导航按钮以及之间的空隙
+        var totalWidth = this._getTotalWidth();
+        //所有button的宽度
+        var buttonWidth = this._calculateButtonsWith();
+        var width = buttonWidth;
+        var showScrollButton = false;
+        if (buttonWidth > totalWidth) {
+            width = totalWidth;
+            showScrollButton = true;
+        }
+        this.scrollLeft.setVisible(showScrollButton);
+        this.scrollRight.setVisible(showScrollButton);
+        //这边动态改变buttongroup的宽度,因为最大宽度是变的
+        this.tab.element.width(width);
+        this._dealWithScrollButtonState();
+        this.scrollSection = width * 2 / 3;
+        this.scrollSelectedVisible();
+    },
+
+    scrollSelectedVisible: function () {
+        var value = this.tab.getValue()[0];
+        //从index 0到当前选中的tab的所有button的宽度
+        var visibleWidth = this._calculateButtonsWith(function (item) {
+            if (item.getValue() === value) {
+                return true;
+            }
+        })
+        var buttonWidth = this._getTotalWidth();
+        var scrollWidth = visibleWidth - buttonWidth / 2;
+        if (this._needScroll(visibleWidth, buttonWidth)) {
+            this._scrollTo(scrollWidth)
+        }
+    },
+
+    getAllButtons: function () {
+        return this.tab.getAllButtons.apply(this.tab, arguments);
+    },
+
+    addItems: function (items) {
+        this.tab.addItems.apply(this.tab, arguments);
+        this.resize();
+        this._scrollToEnd();
+    },
+
+    getValue: function () {
+        this.tab.getValue.apply(this.tab, arguments);
+    },
+
+    setValue: function (v) {
+        this.tab.setValue.apply(this.tab, arguments);
+    },
+
+    populate: function () {
+        this.tab.populate.apply(this.tab, arguments);
+        this.resize();
+    }
+})
+
+BI.DynamicGroupTabButtonGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.dynamic_group_tab_button_group", BI.DynamicGroupTabButtonGroup);/**
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTableCell
+ * @extends BI.Widget
+ */
+BI.ExcelTableCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTableCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.excel_table_cell', BI.ExcelTableCell);/**
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTableHeaderCell
+ * @extends BI.Widget
+ */
+BI.ExcelTableHeaderCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTableHeaderCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table-header-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTableHeaderCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: BI.HorizontalAlign.Center,
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.excel_table_header_cell', BI.ExcelTableHeaderCell);/**
+ * Excel表格
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTable
+ * @extends BI.Widget
+ */
+BI.ExcelTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table",
+            el: {
+                type: "bi.adaptive_table"
+            },
+
+            isNeedResize: false,
+            isResizeAdapt: true,
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 37,
+            footerRowSize: 37,
+            rowSize: 37,
+
+            regionColumnSize: false,
+
+            items: [] //二维数组
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        var mergeCols = [];
+        BI.each(o.mergeCols, function (i, col) {
+            mergeCols.push(col + 1);
+        });
+        this.table = BI.createWidget(o.el, {
+            type: "bi.table_view",
+            element: this,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+
+            isNeedFreeze: false,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: [""].concat(o.columnSize),
+            headerRowSize: 18,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize || [82, ""]
+        });
+
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+        BI.nextTick(function () {
+            self.setRegionColumnSize(o.regionColumnSize || [82, ""]);
+        });
+    },
+
+    resize: function () {
+        this.table.resize();
+    },
+
+    setColumnSize: function (columnSize) {
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    getCalculateColumnSize: function () {
+        return this.table.getCalculateColumnSize();
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize();
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize();
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    resizeHeader: function () {
+        this.table.resize();
+        this.table._resizeHeader && this.table._resizeHeader();
+    },
+
+    attr: function (key,value) {
+        var self = this;
+        if (BI.isObject(key)) {
+            BI.each(key, function (k, v) {
+                self.attr(k, v);
+            });
+            return;
+        }
+        BI.ExcelTable.superclass.attr.apply(this, arguments);
+        switch (key){
+            case "mergeCols":
+                var mCols = [];
+                BI.each(value, function (i, col) {
+                    mCols.push(col + 1);
+                });
+                value=mCols;
+                break;
+        }
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    populate: function (rows) {
+        var self = this;
+        var columnSize = this.getColumnSize();
+        var items = [];
+        var header = [{
+            type: "bi.excel_table_header_cell"
+        }];
+        if (BI.isNotNull(rows)) {
+            BI.each(columnSize, function (i, size) {
+                header.push({
+                    type: "bi.excel_table_header_cell",
+                    text: BI.int2Abc(i + 1)
+                });
+            });
+            BI.each(rows, function (i, row) {
+                items.push([{
+                    type: "bi.excel_table_header_cell",
+                    text: (i + 1)
+                }].concat(row));
+            });
+        }
+        this.table.populate(items, [header]);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.ExcelTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.excel_table', BI.ExcelTable);/**
+ * 文件管理控件组
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerButtonGroup
+ * @extends BI.Widget
+ */
+BI.FileManagerButtonGroup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerButtonGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-button_group",
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerButtonGroup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button_group = BI.createWidget({
+            type: "bi.button_tree",
+            element: this,
+            chooseType: BI.Selection.Multi,
+            items: this._formatItems(o.items),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _formatItems: function (items) {
+        var self = this, o = this.options;
+        BI.each(items, function (i, item) {
+            if (item.children && item.children.length > 0) {
+                item.type = "bi.file_manager_folder_item";
+            } else {
+                item.type = "bi.file_manager_file_item";
+            }
+        });
+        return items;
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getNotSelectedValue: function () {
+        return this.button_group.getNotSelectedValue();
+    },
+
+    getAllLeaves: function () {
+        return this.button_group.getAllLeaves();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    getSelectedButtons: function () {
+        return this.button_group.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.button_group.getNotSelectedButtons();
+    },
+
+    populate: function (items) {
+        this.button_group.populate(this._formatItems(items));
+    }
+});
+BI.FileManagerButtonGroup.EVENT_CHANGE = "FileManagerButtonGroup.EVENT_CHANGE";
+$.shortcut("bi.file_manager_button_group", BI.FileManagerButtonGroup);/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManager
+ * @extends BI.Widget
+ */
+BI.FileManager = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManager.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager",
+            el: {},
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManager.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = new BI.Tree();
+        var items = BI.Tree.transformToTreeFormat(o.items);
+        this.tree.initTree(items);
+        this.selectedValues = [];
+        this.nav = BI.createWidget({
+            type: "bi.file_manager_nav",
+            items: BI.deepClone(items)
+        });
+        this.nav.on(BI.FileManagerNav.EVENT_CHANGE, function (value, obj) {
+            if (value == "-1") {//根节点
+                self.populate({children: self.tree.toJSON()});
+            } else {
+                var node = self.tree.search(obj.attr("id"));
+                self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)}));
+            }
+            self.setValue(self.selectedValues);
+        });
+        this.list = BI.createWidget(o.el, {
+            type: "bi.file_manager_list",
+            items: items
+        });
+        this.list.on(BI.Controller.EVENT_CHANGE, function (type, selected, obj) {
+            if (type === BI.Events.CHANGE) {
+                var node = self.tree.search(obj.attr("id"));
+                self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)}));
+            } else if (type === BI.Events.CLICK) {
+                var values = [];
+                if (obj instanceof BI.MultiSelectBar) {
+                    var t = self.list.getValue();
+                    selected = t.type === BI.Selection.All;
+                    values = BI.concat(t.assist, t.value);
+                } else {
+                    values = obj.getAllLeaves();
+                }
+                BI.each(values, function (i, v) {
+                    if (selected === true) {
+                        self.selectedValues.pushDistinct(v);
+                    } else {
+                        self.selectedValues.remove(v);
+                    }
+                });
+            }
+            self.setValue(self.selectedValues);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.list,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 10
+            }, {
+                el: this.nav,
+                left: 40,
+                right: 100,
+                top: 0
+            }]
+        });
+    },
+
+    setValue: function (value) {
+        this.selectedValues = value || [];
+        this.list.setValue(this.selectedValues);
+    },
+
+    getValue: function () {
+        var obj = this.list.getValue();
+        var res = obj.type === BI.Selection.All ? obj.assist : obj.value;
+        res.pushDistinctArray(this.selectedValues);
+        return res;
+    },
+
+    _populate: function (items) {
+        this.list.populate(items);
+    },
+
+    getSelectedValue: function () {
+        return this.nav.getValue()[0];
+    },
+
+    getSelectedId: function () {
+        return this.nav.getId()[0];
+    },
+
+    populate: function (node) {
+        var clone = BI.deepClone(node);
+        this._populate(node.children);
+        this.nav.populate(clone);
+    }
+});
+BI.FileManager.EVENT_CHANGE = "FileManager.EVENT_CHANGE";
+$.shortcut("bi.file_manager", BI.FileManager);/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerFileItem
+ * @extends BI.Single
+ */
+BI.FileManagerFileItem = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerFileItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-file-item bi-list-item",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerFileItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checked = BI.createWidget({
+            type: "bi.multi_select_bar",
+            text: "",
+            width: 36,
+            height: o.height
+        });
+        this.checked.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.checked,
+                width: 36
+            }, {
+                el: {
+                    type: "bi.icon_button",
+                    cls: "create-by-me-file-font"
+                },
+                width: 20
+            }, {
+                el: {
+                    type: "bi.label",
+                    textAlign: "left",
+                    height: o.height,
+                    text: o.text,
+                    value: o.value
+                }
+            }]
+        })
+    },
+
+    getAllLeaves: function(){
+        return [this.options.value];
+    },
+
+    isSelected: function () {
+        return this.checked.isSelected();
+    },
+
+    setSelected: function (v) {
+        this.checked.setSelected(v);
+    }
+});
+BI.FileManagerFileItem.EVENT_CHANGE = "FileManagerFileItem.EVENT_CHANGE";
+$.shortcut("bi.file_manager_file_item", BI.FileManagerFileItem);/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerFolderItem
+ * @extends BI.Single
+ */
+BI.FileManagerFolderItem = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerFolderItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-folder-item bi-list-item",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerFolderItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checked = BI.createWidget({
+            type: "bi.multi_select_bar",
+            text: "",
+            width: 36,
+            height: o.height
+        });
+        this.checked.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            textAlign: "left",
+            height: o.height,
+            text: o.text,
+            value: o.value
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CHANGE, o.value, self);
+        });
+
+        this.tree = new BI.Tree();
+        this.tree.initTree([{
+            id: o.id,
+            children: o.children
+        }]);
+        this.selectValue = [];
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.checked,
+                width: 36
+            }, {
+                el: {
+                    type: "bi.icon_button",
+                    cls: "create-by-me-folder-font"
+                },
+                width: 20
+            }, {
+                el: this.button
+            }]
+        })
+    },
+
+    setAllSelected: function (v) {
+        this.checked.setSelected(v);
+        this.selectValue = [];
+    },
+
+    setHalfSelected: function (v) {
+        this.checked.setHalfSelected(v);
+        if(!v){
+            this.selectValue = [];
+        }
+    },
+
+    setValue: function (v) {
+        var self = this, o = this.options;
+        var isHalf = false;
+        var selectValue = [];
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                if (BI.contains(v, node.get("data").value)) {
+                    selectValue.push(node.get("data").value);
+                } else {
+                    isHalf = true;
+                }
+            }
+        });
+        this.setAllSelected(selectValue.length > 0 && !isHalf);
+        this.setHalfSelected(selectValue.length > 0 && isHalf);
+        if (this.checked.isHalfSelected()) {
+            this.selectValue = selectValue;
+        }
+    },
+
+    getAllButtons: function () {
+        return [this];
+    },
+
+    getAllLeaves: function () {
+        var o = this.options;
+        var res = [];
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                res.push(node.get("data").value)
+            }
+        });
+        return res;
+    },
+
+    getNotSelectedValue: function () {
+        var self = this, o = this.options;
+        var res = [];
+        var isAllSelected = this.checked.isSelected();
+        if (isAllSelected === true) {
+            return res;
+        }
+        var isHalfSelected = this.checked.isHalfSelected();
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                var v = node.get("data").value;
+                if (isHalfSelected === true) {
+                    if (!BI.contains(self.selectValue, node.get("data").value)) {
+                        res.push(v);
+                    }
+                } else {
+                    res.push(v);
+                }
+            }
+        });
+        return res;
+    },
+
+    getValue: function () {
+        var res = [];
+        if (this.checked.isSelected()) {
+            this.tree.traverse(function (node) {
+                if (node.isLeaf()) {
+                    res.push(node.get("data").value);
+                }
+            });
+            return res;
+        }
+        if (this.checked.isHalfSelected()) {
+            return this.selectValue;
+        }
+        return [];
+    }
+});
+BI.FileManagerFolderItem.EVENT_CHANGE = "FileManagerFolderItem.EVENT_CHANGE";
+$.shortcut("bi.file_manager_folder_item", BI.FileManagerFolderItem);/**
+ * 文件管理控件列表
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerList
+ * @extends BI.Widget
+ */
+BI.FileManagerList = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-list",
+            el: {},
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerList.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.list = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            items: o.items,
+            toolbar: {
+                type: "bi.multi_select_bar",
+                height: 40,
+                text: ""
+            },
+            el: {
+                type: "bi.list_pane",
+                el: BI.isWidget(o.el) ? o.el : BI.extend({
+                    type: "bi.file_manager_button_group"
+                }, o.el)
+            }
+        });
+        this.list.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        this.list.setValue({
+            value: v
+        });
+    },
+
+    getValue: function () {
+        return this.list.getValue();
+    },
+
+    populate: function (items) {
+        this.list.populate(items);
+        this.list.setToolBarVisible(true);
+    }
+});
+BI.FileManagerList.EVENT_CHANGE = "FileManagerList.EVENT_CHANGE";
+$.shortcut("bi.file_manager_list", BI.FileManagerList);/**
+ * 文件管理导航按钮
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerNavButton
+ * @extends BI.Widget
+ */
+BI.FileManagerNavButton = BI.inherit(BI.Widget, {
+
+    _const: {
+        normal_color: "#ffffff",
+        select_color: "#f4f4f4"
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerNavButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-nav-button",
+            selected: false,
+            height: 40
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerNavButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            cls: "file-manager-nav-button-text",
+            once: true,
+            selected: o.selected,
+            text: o.text,
+            title: o.text,
+            value: o.value,
+            height: o.height,
+            lgap: 20,
+            rgap: 10
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var svg = BI.createWidget({
+            type: "bi.svg",
+            cls: "file-manager-nav-button-triangle",
+            width: 15,
+            height: o.height
+        });
+        var path = svg.path("M0,0L15,20L0,40").attr({
+            "stroke": c.select_color,
+            "fill": o.selected ? c.select_color : c.normal_color
+        });
+        this.button.on(BI.TextButton.EVENT_CHANGE, function () {
+            if (this.isSelected()) {
+                path.attr("fill", c.select_color);
+            } else {
+                path.attr("fill", c.normal_color);
+            }
+        });
+        BI.createWidget({
+            type: "bi.default",
+            element: this,
+            items: [this.button]
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: svg,
+                right: -15,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    isSelected: function () {
+        return this.button.isSelected();
+    },
+
+    setValue: function (v) {
+        this.button.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button.getValue();
+    },
+
+    populate: function (items) {
+
+    }
+});
+BI.FileManagerNavButton.EVENT_CHANGE = "FileManagerNavButton.EVENT_CHANGE";
+$.shortcut("bi.file_manager_nav_button", BI.FileManagerNavButton);/**
+ * 文件管理导航
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerNav
+ * @extends BI.Widget
+ */
+BI.FileManagerNav = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerNav.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-nav",
+            height: 40,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerNav.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = new BI.Tree();
+        this.refreshTreeData(o.items);
+        this.tree.getRoot().set("data", {
+            text: BI.i18nText("BI-Created_By_Me"),
+            value: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+            id: BI.FileManagerNav.ROOT_CREATE_BY_ME
+        });
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: [{
+                type: "bi.file_manager_nav_button",
+                text: BI.i18nText("BI-Created_By_Me"),
+                selected: true,
+                id: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+                value: BI.FileManagerNav.ROOT_CREATE_BY_ME
+            }],
+            layouts: [{
+                type: "bi.horizontal"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.FileManagerNav.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _getAllParents: function (id) {
+        var node, res = [];
+        if (!id) {
+            node = this.tree.getRoot();
+        } else {
+            node = this.tree.search(id);
+        }
+        while (node.parent) {
+            res.push(node);
+            node = node.parent;
+        }
+        res.push(node);
+        return res.reverse();
+    },
+
+    _formatNodes: function (nodes) {
+        var res = [];
+        BI.each(nodes, function (i, node) {
+            res.push(BI.extend({
+                type: "bi.file_manager_nav_button",
+                id: node.id
+            }, node.get("data")));
+        });
+        BI.last(res).selected = true;
+        return res;
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getId: function () {
+        var ids = [];
+        BI.each(this.button_group.getSelectedButtons(), function (i, btn) {
+            ids.push(btn.attr("id"));
+        });
+        return ids;
+    },
+
+    refreshTreeData: function(items){
+        this.tree.initTree(BI.Tree.transformToTreeFormat(items));
+        this.tree.getRoot().set("data", {
+            text: BI.i18nText("BI-Created_By_Me"),
+            value: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+            id: BI.FileManagerNav.ROOT_CREATE_BY_ME
+        });
+    },
+
+    populate: function (node) {
+        var parents = BI.isNull(node) ? [this.tree.getRoot()] : this._getAllParents(node.id);
+        this.button_group.populate(this._formatNodes(parents));
+    }
+});
+BI.extend(BI.FileManagerNav, {
+    ROOT_CREATE_BY_ME: "-1"
+});
+BI.FileManagerNav.EVENT_CHANGE = "FileManagerNav.EVENT_CHANGE";
+$.shortcut("bi.file_manager_nav", BI.FileManagerNav);/**
+ * 过滤条件抽象类
+ *
+ * @class BI.AbstractFilterItem
+ * @extend BI.Widget
+ */
+BI.AbstractFilterItem = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.AbstractFilterItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-item"
+        })
+    },
+
+    _init: function () {
+        BI.AbstractFilterItem.superclass._init.apply(this, arguments);
+    },
+
+    isSelectedCondition: function () {
+        return this.emptyItem && this.emptyItem.isVisible();
+    },
+
+    setSelectedCondition: function (b) {
+        if (!!b) {
+            if (!this.emptyItem) {
+                this.emptyItem = BI.createWidget({
+                    type: "bi.absolute",
+                    height: 40,
+                    cls: "filter-item-empty-item",
+                    items: [{
+                        el: {
+                            type: "bi.center_adapt",
+                            cls: "empty-filter-item-leaf"
+                        }
+                    }],
+                    hgap: 10,
+                    vgap: 5
+                });
+                BI.createWidget({
+                    type: "bi.vertical",
+                    element: this,
+                    items: [this.emptyItem],
+                    scrolly: false
+                });
+            }
+        }
+        this.emptyItem && this.emptyItem.setVisible(b);
+    }
+});/**
+ * @class BI.FilterExpander
+ * @extend BI.AbstractFilterItem
+ * 过滤树的一个expander节点
+ */
+BI.FilterExpander = BI.inherit(BI.AbstractFilterItem, {
+
+    _constant: {
+        EXPANDER_WIDTH: 20
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.FilterExpander.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-filter-expander",
+            el: {},
+            popup: {}
+        })
+    },
+
+    _init: function () {
+        BI.FilterExpander.superclass._init.apply(this, arguments);
+        this._initExpander();
+        this._initConditionsView();
+        BI.createWidget({
+            type: "bi.horizontal_adapt",
+            element: this,
+            items: [this.expander, this.conditionsView]
+        });
+    },
+
+    _initExpander: function () {
+        var self = this, o = this.options;
+        var value = o.value, text = "";
+        if (value === BICst.FILTER_TYPE.AND) {
+            text = BI.i18nText("BI-Basic_And");
+        } else {
+            text = BI.i18nText("BI-Basic_Or");
+        }
+        this.expander = BI.createWidget({
+            type: "bi.text_button",
+            cls: "condition-and-or",
+            text: text,
+            value: value,
+            id: o.id,
+            width: this._constant.EXPANDER_WIDTH,
+            height: "100%"
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _initConditionsView: function () {
+        var self = this, popup = this.options.popup;
+        this.conditionsView = BI.createWidget(popup);
+        this.conditionsView.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    getValue: function () {
+        return {
+            type: this.expander.getValue(),
+            value: this.conditionsView.getValue(),
+            id: this.options.id
+        };
+    },
+
+    setValue: function () {
+
+    },
+
+    populate: function (items) {
+        this.conditionsView.populate.apply(this.conditionsView, arguments);
+    }
+});
+$.shortcut("bi.filter_expander", BI.FilterExpander);/**
+ * 过滤
+ *
+ * Created by GUY on 2015/11/20.
+ * @class BI.Filter
+ * @extend BI.Widget
+ */
+BI.Filter = BI.inherit(BI.Widget, {
+
+    constants: {
+        FIELD_TYPE_NUMBER: 1,
+        FIELD_TYPE_STRING: 0,
+        FIELD_TYPE_DATE: 2
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Filter.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter",
+            expander: {},
+            items: [],
+            el: {},
+            itemCreator: BI.empty
+        })
+    },
+
+    _init: function () {
+        BI.Filter.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.filter = BI.createWidget(o.el,{
+            type: "bi.filter_operation",
+            expander: o.expander,
+            items: o.items,
+            element: this
+        });
+        this.filter.on(BI.FilterOperation.EVENT_OPERATION, function (type) {
+            switch (type) {
+                case BICst.FILTER_OPERATION_CONDITION:
+                case BICst.FILTER_OPERATION_CONDITION_AND:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_CONDITION);
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION_OR:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_CONDITION, 1);
+                    break;
+                case BICst.FILTER_OPERATION_FORMULA:
+                case BICst.FILTER_OPERATION_FORMULA_AND:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_FORMULA);
+                    break;
+                case BICst.FILTER_OPERATION_FORMULA_OR:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_FORMULA, 1);
+                    break;
+            }
+        });
+        this.filter.on(BI.FilterOperation.EVENT_DESTROY_ITEM, function (id) {
+            self._removeCondition(id);
+        });
+
+        this.tree = new BI.Tree();
+        this.tree.initTree(o.items);
+    },
+
+    _removeCondition: function (id) {
+        var finded = this.tree.search(id);
+        if (BI.isNotNull(finded)) {
+            var parent = finded.getParent();
+            parent.removeChild(id);
+            if (parent.getChildrenLength() <= 1) {
+                var prev = parent.getParent();
+                if (BI.isNotNull(prev)) {
+                    var index = prev.getChildIndex(parent.id);
+                    prev.removeChildByIndex(index);
+                    if (parent.getChildrenLength() === 1) {
+                        prev.addChild(parent.getFirstChild(), index);
+                    }
+                }
+            }
+            this._populate(this.tree.toJSONWithNode());
+            this.fireEvent(BI.Filter.EVENT_CHANGE);
+        }
+    },
+
+    _createEmptyNode: function (type) {
+        var node = new BI.Node(BI.UUID());
+        node.set("data", {
+            value: type
+        });
+        return node;
+    },
+
+    _insertAndOrCondition: function (id, formulaOrField, type) {
+        var ANDOR = ["AND", "OR"];
+        type || (type = 0);
+        var finded = this.tree.search(id);
+        if (BI.isNotNull(finded)) {
+            var data = finded.get("data");
+            var parent = finded.getParent();
+            var index = parent.getChildIndex(finded.id);
+            var pdata = parent.get("data") || {};
+            var node = this._createEmptyNode(formulaOrField);
+            if (data.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                this.tree.addNode(finded, node);
+                return;
+            }
+            if (data.value === BICst.FILTER_TYPE[ANDOR[1 - type]]) {
+                if (pdata.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                    parent.addChild(node, index + 1);
+                    return;
+                }
+            }
+            if ((data.value === BICst.FILTER_TYPE[ANDOR[1 - type]] && pdata.value !== BICst.FILTER_TYPE[ANDOR[type]])
+                || pdata.value === BICst.FILTER_TYPE[ANDOR[1 - type]]
+                || (pdata.value !== BICst.FILTER_TYPE.AND && pdata.value !== BICst.FILTER_TYPE.OR)) {
+                var andor = new BI.Node(BI.UUID());
+                andor.set("data", {
+                    value: BICst.FILTER_TYPE[ANDOR[type]],
+                    children: [finded.get("data"), node.get("data")]
+                });
+                parent.removeChildByIndex(index);
+                parent.addChild(andor, index);
+                andor.addChild(finded);
+                andor.addChild(node);
+                return;
+            }
+            parent.addChild(node, index + 1);
+        }
+    },
+
+    _addAndOrCondition: function (formulaOrField, type) {
+        var ANDOR = ["AND", "OR"];
+        type || (type = 0);
+        var o = this.options;
+        var currentSelectItem = this.filter.getCurrentSelectItem();
+        if (BI.isNotNull(currentSelectItem)) {
+            var id = currentSelectItem.attr("id");
+            this._insertAndOrCondition(id, formulaOrField, type);
+        } else {
+            var node = this._createEmptyNode(formulaOrField);
+            var root = this.tree.getRoot();
+            var child = root.getLastChild();
+            if (BI.isNotNull(child)) {
+                var data = child.get("data");
+                if (data.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                    this.tree.addNode(child, node);
+                } else {
+                    var andor = new BI.Node(BI.UUID());
+                    andor.set("data", {
+                        value: BICst.FILTER_TYPE[ANDOR[type]],
+                        children: [child.get("data"), node.get("data")]
+                    });
+                    root.removeChild(child.id);
+                    this.tree.addNode(andor);
+                    this.tree.addNode(andor, child);
+                    this.tree.addNode(andor, node);
+                }
+            } else {
+                this.tree.addNode(node);
+            }
+        }
+        this._populate(this.tree.toJSONWithNode());
+        this.fireEvent(BI.Filter.EVENT_CHANGE);
+    },
+
+    _populate: function (items) {
+        var self = this, o = this.options;
+        o.items = items;
+        ArrayUtils.traversal(items, function (i, item) {
+            o.itemCreator(item);
+        });
+        this.filter.populate.apply(this.filter, [items]);
+    },
+
+    populate: function (conditions) {
+        this.tree.initTree(conditions);
+        this._populate(this.tree.toJSONWithNode());
+    },
+
+    getValue: function () {
+        return this.filter.getValue();
+    }
+});
+BI.Filter.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.filter", BI.Filter);/**
+ * 过滤条件
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.FilterOperation
+ * @extend BI.Widget
+ */
+BI.FilterOperation = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FilterOperation.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-operation",
+            expander: {},
+            items: [],
+            selections: [BICst.FILTER_OPERATION_CONDITION, BICst.FILTER_OPERATION_FORMULA],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _defaultState: function () {
+        if (BI.isNotNull(this.currentSelected)) {
+            this.currentSelected.setSelectedCondition(false);
+        }
+        this.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+    },
+
+    _init: function () {
+        BI.FilterOperation.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.currentSelected = null;
+
+        this.filter = BI.createWidget({
+            type: "bi.filter_pane",
+            expander: o.expander,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+        this.filter.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (type === BI.Events.CLICK) {
+                if (BI.isNotNull(self.currentSelected) && self.currentSelected === obj) {
+                    obj.setSelectedCondition(!obj.isSelectedCondition());
+                } else {
+                    if (BI.isNotNull(self.currentSelected)) {
+                        self.currentSelected.setSelectedCondition(false);
+                    }
+                    self.currentSelected = obj;
+                    obj.setSelectedCondition(true);
+                }
+                if (self.currentSelected.isSelectedCondition()) {
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_ANDOR_CONDITION);
+                } else {
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+                }
+            }
+            if (type === BI.Events.DESTROY) {
+                if (self.currentSelected === obj) {
+                    self.currentSelected = null;
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+                }
+                self.fireEvent(BI.FilterOperation.EVENT_DESTROY_ITEM, value, obj);
+            }
+        });
+        this.filter.on(BI.FilterPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FilterOperation.EVENT_CHANGE, arguments);
+        });
+        var operation = this._buildOperationTab();
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: operation,
+                height: 40
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    scrollable: true,
+                    items: [{
+                        el: {
+                            type: "bi.left",
+                            items: [
+                                this.filter
+                            ]
+                        },
+                        top: 0,
+                        right: 2,
+                        bottom: 0,
+                        left: 0
+                    }]
+                }
+            }]
+        })
+    },
+
+    _buildOperationTab: function () {
+        this.buttonComboTab = BI.createWidget({
+            type: "bi.tab",
+            tab: null,
+            cardCreator: BI.bind(this._createTabs, this)
+        });
+        this.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+        return this.buttonComboTab;
+    },
+
+    _createTabs: function (v) {
+        var self = this;
+        switch (v) {
+            case BI.FilterOperation.OPERATION_ADD_CONDITION:
+                var btnGroup = BI.createWidget({
+                    type: "bi.button_group",
+                    items: BI.createItems(self._createButtons(), {
+                        type: "bi.button",
+                        forceNotSelected: true,
+                        level: "ignore",
+                        height: 25
+                    }),
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                    layouts: [{
+                        type: "bi.right",
+                        hgap: 10,
+                        vgap: 5
+                    }]
+                });
+                btnGroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+                    self.fireEvent(BI.FilterOperation.EVENT_OPERATION, obj.getValue());
+                    self._defaultState();
+                });
+                return btnGroup;
+            case BI.FilterOperation.OPERATION_ADD_ANDOR_CONDITION:
+                var btnGroup = BI.createWidget({
+                    type: "bi.button_group",
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                    items: self._createCombos(),
+                    layouts: [{
+                        type: "bi.right",
+                        hgap: 10,
+                        vgap: 5
+                    }]
+                });
+                return btnGroup;
+        }
+    },
+
+    _createButtons: function(){
+        var buttons = [];
+        BI.each(this.options.selections, function(i, type){
+            switch (type){
+                case BICst.FILTER_OPERATION_FORMULA:
+                    buttons.push({
+                        text: BI.i18nText("BI-Add_Formula"),
+                        value: BICst.FILTER_OPERATION_FORMULA
+                    });
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION:
+                    buttons.push({
+                        text: BI.i18nText("BI-Add_Condition"),
+                        value: BICst.FILTER_OPERATION_CONDITION
+                    });
+                    break;
+            }
+        });
+        return buttons;
+    },
+
+    _createCombos: function () {
+        var self = this, combos = [];
+        BI.each(this.options.selections, function(i, type){
+            var text = "", items = [];
+            switch (type) {
+                case BICst.FILTER_OPERATION_FORMULA:
+                    text = BI.i18nText("BI-Add_Formula");
+                    items = BICst.FILTER_ADD_FORMULA_COMBO;
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION:
+                    text = BI.i18nText("BI-Add_Condition");
+                    items = BICst.FILTER_ADD_CONDITION_COMBO;
+                    break;
+            }
+            var addCombo = BI.createWidget({
+                type: "bi.static_combo",
+                text: text,
+                width: 90,
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_NONE,
+                items: BI.createItems(items, {
+                    type: "bi.single_select_item",
+                    height: 25
+                })
+            });
+            addCombo.on(BI.Combo.EVENT_CHANGE, function (value, obj) {
+                self.fireEvent(BI.FilterOperation.EVENT_OPERATION, obj.getValue());
+                self._defaultState();
+            });
+            combos.push(addCombo);
+        });
+        return combos;
+    },
+
+    getCurrentSelectItem: function () {
+        if (BI.isNotNull(this.currentSelected) && this.currentSelected.isSelectedCondition()) {
+            return this.currentSelected;
+        }
+    },
+
+    populate: function (items) {
+
+        this.filter.populate.apply(this.filter, arguments);
+    },
+
+    getValue: function () {
+        return this.filter.getValue();
+    }
+});
+BI.extend(BI.FilterOperation, {
+    OPERATION_ADD_CONDITION: 0,
+    OPERATION_ADD_ANDOR_CONDITION: 1
+});
+BI.FilterOperation.EVENT_OPERATION = "EVENT_OPERATION";
+BI.FilterOperation.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FilterOperation.EVENT_DESTROY_ITEM = "BI.FilterOperation.EVENT_DESTROY_ITEM";
+$.shortcut("bi.filter_operation", BI.FilterOperation);/**
+ * @class BI.FilterPane
+ * @extend BI.Widget
+ * 过滤面板
+ */
+BI.FilterPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FilterPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-pane",
+            expander: {},
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.FilterPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.filter_expander",
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            }, o.expander),
+            el: {
+                type: "bi.button_map",
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                layouts: [{
+                    type: "bi.vertical",
+                    scrolly: false
+                }]
+            }
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.FilterPane.EVENT_CHANGE, [].slice.call(arguments, 1));
+            }
+        });
+
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+    },
+
+    populate: function (items) {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    }
+});
+BI.FilterPane.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.filter_pane", BI.FilterPane);/**
+ * Created by windy on 2017/3/13.
+ * 数值微调器
+ */
+BI.FineTuningNumberEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FineTuningNumberEditor.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-fine-tuning-number-editor",
+            value: -1
+        })
+    },
+
+    _init: function () {
+        BI.FineTuningNumberEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            value: this._alertInEditorValue(o.value),
+            errorText: BI.i18nText("BI-Please_Input_Natural_Number"),
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v) || self._alertOutEditorValue(v) === -1;
+            }
+        });
+        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function(){
+            self._finetuning(0);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this.topBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "column-pre-page-h-font top-button"
+        });
+        this.topBtn.on(BI.IconButton.EVENT_CHANGE, function(){
+            self._finetuning(1);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this.bottomBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "column-next-page-h-font bottom-button"
+        });
+        this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function(){
+            self._finetuning(-1);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this._finetuning(0);
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [this.editor, {
+                el: {
+                    type: "bi.grid",
+                    columns: 1,
+                    rows: 2,
+                    items: [{
+                        column: 0,
+                        row: 0,
+                        el: this.topBtn
+                    }, {
+                        column: 0,
+                        row: 1,
+                        el: this.bottomBtn
+                    }]
+                },
+                width: 30
+            }]
+        });
+    },
+
+    _alertOutEditorValue: function(v){
+        return v === BI.i18nText("BI-Basic_Auto") ? -1 : v;
+    },
+
+    _alertInEditorValue: function(v){
+        return BI.parseInt(v) === -1 ? BI.i18nText("BI-Basic_Auto") : v;
+    },
+
+    //微调
+    _finetuning: function(add){
+        var v = BI.parseInt(this._alertOutEditorValue(this.editor.getValue()));
+        this.editor.setValue(this._alertInEditorValue(v + add));
+        this.bottomBtn.setEnable((v + add) !== -1);
+    },
+
+    getValue: function () {
+        var v = this.editor.getValue();
+        return this._alertOutEditorValue(v);
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(this._alertInEditorValue(v));
+        this._finetuning(0);
+    }
+
+});
+BI.FineTuningNumberEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.fine_tuning_number_editor", BI.FineTuningNumberEditor);/**
+ * Created by roy on 15/9/29.
+ */
+/**
+ * Created by roy on 15/9/1.
+ */
+BI.SymbolGroup = BI.inherit(BI.Widget, {
+    constants: {
+        hgap: 7.5,
+        textWidth: 14,
+        textHeight: 17
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.SymbolGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-symbol-group"
+        })
+    },
+    _init: function () {
+        BI.SymbolGroup.superclass._init.apply(this, arguments)
+        var self = this, c = this.constants;
+
+        var items = [{
+            text: "+",
+            value: "+"
+        }, {
+            text: "-",
+            value: "-"
+        }, {
+            text: "*",
+            value: "*"
+        }, {
+            text: "/",
+            value: "/"
+        }, {
+            text: "(",
+            value: "("
+        }, {
+            text: ")",
+            value: ")"
+        }];
+
+        this.symbolgroup = BI.createWidget({
+            type: "bi.button_group",
+            element: self,
+            chooseType:-1,
+            items: BI.createItems(items, {
+                type: "bi.text_button",
+                forceNotSelected: true,
+                once: false,
+                textWidth: c.textWidth,
+                textHeight: c.textHeight,
+                cls: "symbol-button"
+            }),
+            layouts: [{
+                type: "bi.left_vertical_adapt",
+                hgap: c.hgap
+            }]
+        });
+
+        this.symbolgroup.on(BI.ButtonGroup.EVENT_CHANGE,function(v){
+            self.fireEvent(BI.SymbolGroup.EVENT_CHANGE,v)
+        })
+    }
+});
+BI.SymbolGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.symbol_group", BI.SymbolGroup);/**
+ * Created by roy on 15/9/9.
+ */
+//0更多函数为展开状态,1为函数框展开,显示返回状态
+BI.FormulaInsert = BI.inherit(BI.Widget, {
+    constants: {
+        right_set_off: -322,
+        height: 30,
+        width: 160,
+        right: 10,
+        button_bottom: 5,
+        pane_bottom: -1,
+        retract: 1,
+        more_function: 0,
+        functionTypes: ["MATH", "DATETIME", "ARRAY", "TEXT", "LOGIC", "OTHER"],
+        abandonFunctions: ["ACOS", "ACOSH", "ASIN", "ASINH", "ATAN", "ATAN2", "ATANH", "BITNOT", "BITOPERATION", "CHAR", "CLASS", "CODE", "COMBIN", "CORREL", "COS", "COSH", "DATETONUMBER", "DEGREES", "GETKEY", "GETUSERDEPARTMENTS", "GETUSERJOBTITLES", "NVL", "ODD", "PI", "POWER", "PRODUCT", "PROPER", "RADIANS", "REGEXP", "REVERSE", "RemoteIP", "SIN", "SINH", "STARTWITH", "TAN", "TANH", "TESTCONNECTION", "TESTMACANDUUID", "TOBINARY", "TOHEX", "TOOCTAL", "TOIMAGE"]
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.FormulaInsert.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-formula-insert",
+            fieldItems: []
+
+
+        })
+    },
+
+    _init: function () {
+        BI.FormulaInsert.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this.constants;
+        self.validation = "valid";
+
+        this.formulatree = BI.createWidget({
+            type: "bi.formula_field_tree",
+            cls: "bi-formula-field-pane",
+            items: o.fieldItems
+        });
+
+        this.formulatree.on(BI.FormulaFieldTree.EVENT_CHANGE, function () {
+            var v = self.formulatree.getValue();
+            self.formulaedit.insertField(self.fieldValueTextMap[v[0]]);
+        });
+
+        this.symbolgroup = BI.createWidget({
+            type: "bi.symbol_group",
+            height: c.height,
+            cls: "symbol-group-column"
+        });
+
+        this.symbolgroup.on(BI.SymbolGroup.EVENT_CHANGE, function (v) {
+            self.formulaedit.insertOperator(v);
+        });
+
+
+        this.formulaedit = BI.createWidget({
+            type: "bi.formula",
+            tipType: "warning",
+            watermark: BI.i18nText("BI-Formula_Water_Mark")
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_CHANGE, function () {
+            if (BI.Func.checkFormulaValidation(self.formulaedit.getCheckString())) {
+                self.validation = "valid";
+                BI.Bubbles.hide(self.getName() + "invalid");
+            } else {
+                BI.Bubbles.show(self.getName() + "invalid", BI.i18nText("BI-Formula_Valid"), self, {
+                    offsetStyle: "center"
+                });
+                self.validation = "invalid"
+            }
+            self.fireEvent(BI.FormulaInsert.EVENT_CHANGE);
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_BLUR, function () {
+            BI.Bubbles.hide(self.getName() + "invalid");
+            if (!self.checkValidation()) {
+                self.formulaedit.setTitle(BI.i18nText("BI-Formula_Valid"), {belowMouse: true});
+            }
+
+
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_FOCUS, function () {
+            self.formulaedit.setTitle("");
+            if (!self.checkValidation()) {
+                BI.Bubbles.show(self.getName() + "invalid", BI.i18nText("BI-Formula_Valid"), self, {offsetStyle: "center"});
+            }
+        });
+
+        this.editorpane = BI.createWidget({
+            type: "bi.vtape",
+
+            items: [
+                {
+                    height: "fill",
+                    el: self.formulaedit
+                }, {
+                    height: c.height,
+                    el: self.symbolgroup
+                }
+            ]
+        });
+
+
+        this.functionbutton = BI.createWidget({
+            type: "bi.text_button",
+            text: BI.i18nText("BI-Formula_More_Function"),
+            value: c.more_function,
+            cls: "more-function-button"
+        });
+
+        this.functionpane = BI.createWidget({
+            type: "bi.function_pane",
+            items: self._createFunctionItems(),
+        });
+
+        this.functionCombo = BI.createWidget({
+            type: "bi.combo",
+            isNeedAdjustWidth: false,
+            el: this.functionbutton,
+            direction: "right,top",
+            adjustYOffset: -16,
+            adjustXOffset: 10,
+            hideChecker: function () {
+                return false;
+            },
+            popup: {
+                el: self.functionpane,
+                width: 372
+            },
+            width: 65
+        });
+
+
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    width: c.width,
+                    el: self.formulatree
+                },
+                {
+
+                    el: self.editorpane
+                }
+            ],
+            height: o.height,
+            width: o.width
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.absolute",
+            items: [
+                {
+                    el: self.functionCombo,
+                    right: c.right,
+                    bottom: c.button_bottom
+                }
+            ]
+        });
+
+
+        self.formulaedit.element.droppable({
+            accept: ".bi-tree-text-leaf-item",
+            drop: function (event, ui) {
+                var value = ui.helper.attr("text");
+                self.formulaedit.insertField(value);
+            }
+        });
+
+
+        this.functionCombo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.functionbutton.setText(BI.i18nText("BI-Formula_Retract"))
+        });
+
+        this.functionCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.functionbutton.setText(BI.i18nText("BI-Formula_More_Function"))
+        });
+
+        this.functionpane.on(BI.FunctionPane.EVENT_INSET, function (v) {
+            if (BI.isNotEmptyString(v)) {
+                self.formulaedit.insertFunction(v);
+            }
+
+        });
+
+        this.populate(o.fieldItems);
+
+    },
+
+
+    _isFunction: function (str) {
+        var self = this, o = this.options, result = false;
+        BI.each(o.functionItems, function (i, item) {
+            var text = item.text.toLowerCase();
+            var lowerString = str.toLowerCase();
+            if (text === lowerString) {
+                result = true
+            }
+        });
+        return result;
+    },
+
+    _analyzeContent: function (v) {
+        var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)|\n/g;
+        return v.match(regx);
+    },
+
+    _getFunctionType: function (functionType) {
+        switch (functionType) {
+            case  "MATH":
+                return BICst.FUNCTION.MATH;
+            case "TEXT":
+                return BICst.FUNCTION.TEXT;
+            case "DATETIME":
+                return BICst.FUNCTION.DATE;
+            case "ARRAY":
+                return BICst.FUNCTION.ARRAY;
+            case "LOGIC":
+                return BICst.FUNCTION.LOGIC;
+            case "OTHER":
+                return BICst.FUNCTION.OTHER;
+        }
+    },
+
+    _createFunctionItems: function () {
+        var self = this;
+        var functionObjs = FormulaJSONs;
+        var functionItems = [];
+        BI.each(functionObjs, function (i, functionObj) {
+            if (self.constants.functionTypes.contains(functionObj.type) && !self.constants.abandonFunctions.contains(functionObj.name)) {
+                var item = {};
+                item.text = functionObj.name;
+                item.value = functionObj.name;
+                item.fieldType = self._getFunctionType(functionObj.type);
+                item.description = functionObj.def;
+                item.title = functionObj.def;
+                functionItems.push(item);
+            }
+        });
+        this.options.functionItems = functionItems;
+        return functionItems;
+    },
+
+    _createFieldTextValueMap: function (fieldItems) {
+        var fieldMap = {};
+        BI.each(fieldItems, function(idx, typeItems){
+            BI.each(typeItems, function (i, fieldItem) {
+                fieldMap[fieldItem.text] = fieldItem.value;
+            });
+        })
+        return fieldMap;
+    },
+
+    _createFieldValueTextMap: function (fieldItems) {
+        var fieldMap = {};
+        BI.each(fieldItems, function (idx, typeItems) {
+            BI.each(typeItems, function (i, fieldItem) {
+                fieldMap[fieldItem.value] = fieldItem.text;
+            })
+        });
+        return fieldMap;
+    },
+
+    _bindDragEvent: function () {
+        var self = this;
+        BI.each(self.formulatree.getAllLeaves(), function (i, node) {
+            node.element.draggable({
+                cursorAt: {top: 5, left: 5},
+                helper: function () {
+                    var hint = BI.createWidget({
+                        type: "bi.helper",
+                        value: node.getValue(),
+                        text: self.fieldValueTextMap[node.getValue()]
+                    });
+                    BI.createWidget({
+                        element: self,
+                        type: "bi.default",
+                        items: [hint]
+                    });
+                    hint.element.attr({text: self.fieldValueTextMap[node.getValue()]});
+                    return hint.element;
+
+                }
+            })
+
+        });
+    },
+
+
+    checkValidation: function () {
+        return this.validation === "valid";
+    },
+
+    refresh: function () {
+        this.formulaedit.refresh();
+    },
+
+    setValue: function (v) {
+        var self = this, result;
+        self.formulaedit.refresh();
+        self.formulaedit.setValue("");
+        result = this._analyzeContent(v || "");
+        BI.each(result, function (i, item) {
+            var fieldRegx = /\$[\{][^\}]*[\}]/;
+            var str = item.match(fieldRegx);
+            if (BI.isNotEmptyArray(str)) {
+                self.formulaedit.insertField(self.fieldValueTextMap[str[0].substring(2, item.length - 1)]);
+            } else if (self._isFunction(item)) {
+                self.formulaedit.setFunction(item);
+            } else {
+                self.formulaedit.insertString(item);
+            }
+        })
+
+    },
+
+    getFormulaString: function () {
+        return this.formulaedit.getFormulaString();
+    },
+
+    getUsedFields: function () {
+        return this.formulaedit.getUsedFields();
+    },
+
+    getValue: function () {
+        return this.formulaedit.getValue();
+    },
+    populate: function (fieldItems) {
+        this.options.fieldItems = fieldItems;
+        this.fieldTextValueMap = this._createFieldTextValueMap(fieldItems);
+        this.fieldValueTextMap = this._createFieldValueTextMap(fieldItems);
+        this.formulaedit.setFieldTextValueMap(this.fieldTextValueMap);
+        this.formulatree.populate(fieldItems);
+        this._bindDragEvent();
+    }
+
+
+});
+BI.FormulaInsert.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_insert", BI.FormulaInsert);BI.ButtonTextTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ButtonTextTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-button-text-tree-item ",
+            id: "",
+            pId: "",
+            height: 25,
+            hgap: 0,
+            lgap: 0,
+            rgap: 0
+        })
+    },
+    _init: function () {
+        BI.ButtonTextTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            lgap: o.lgap,
+            rgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            height: 25,
+            stopEvent:true,
+            value: BI.i18nText("BI-Formula_Insert"),
+            cls: "formula-function-insert-button"
+        });
+        this.button.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.ADD, self.text.getText());
+        });
+        this.button.invisible();
+        this.leaf = BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.button,
+                width: 30
+            }, {
+                el: this.text
+            }],
+            hgap: o.hgap
+        })
+        this.element.hover(function () {
+            self.button.visible();
+        }, function () {
+            if (!self.isSelected()) {
+                self.button.invisible();
+            }
+
+        })
+
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setSelected: function (b) {
+        BI.ButtonTextTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        if (BI.isNotNull(b) && b === true) {
+            this.button.visible();
+        } else {
+            this.button.invisible();
+        }
+    },
+
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    }
+});
+
+$.shortcut("bi.button_text_tree_leaf_item", BI.ButtonTextTreeLeafItem);/**
+ * Created by roy on 15/9/14.
+ */
+BI.FunctionPane = BI.inherit(BI.Widget, {
+    constants: {
+        search_height: 20,
+        height: 200,
+        width: 370,
+        column_size_editor: 170,
+        column_size_right: 200,
+        row_size: 30,
+        hgap: 10,
+        vgap: 10,
+        hgap_offset: 5
+    },
+    _defaultConfig: function () {
+        var conf = BI.FunctionPane.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-formula-function-pane",
+            width: 320,
+            height: 200,
+            items: []
+        })
+    },
+    _init: function () {
+        BI.FunctionPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this.constants;
+
+
+        this.desLabel = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "normal",
+            textWidth: 180
+        });
+
+        this.searchFunctionTree = BI.createWidget({
+            type: "bi.function_tree",
+            cls: "style-top",
+            redmark: function (val, ob) {
+                return true
+            }
+        });
+
+        this.functiontree = BI.createWidget({
+            type: "bi.function_tree",
+            cls: "style-top",
+            items: o.items
+        });
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            adapter: this.functiontree,
+            isAutoSearch: false,
+            onSearch: function (op, populate) {
+                var keyword = op.keyword.toLowerCase();
+                var resultArray = [];
+                BI.each(o.items, function (i, item) {
+                    if (item.value.toLowerCase().indexOf(keyword) > -1 && !BI.isEmptyString(keyword)) {
+                        resultArray.push(item);
+                    }
+                });
+                populate(resultArray, keyword);
+            },
+            el: {
+                type: "bi.small_search_editor"
+            },
+            popup: {
+                type: "bi.function_searcher_pane",
+                searcher: self.searchFunctionTree
+            },
+            height: 25,
+            width: 160
+        });
+
+
+        this.functionLabel = BI.createWidget({
+            type: "bi.label"
+        });
+
+        BI.createWidget({
+            element: this,
+            type: "bi.window",
+            width: c.width,
+            cls: "style-out",
+            columns: 2,
+            rows: 2,
+            columnSize: [c.column_size_editor, c.column_size_right],
+            rowSize: [c.row_size, 'fill'],
+            items: [
+                [
+                    {
+
+                        el: {
+                            type: "bi.center_adapt",
+                            hgap: c.hgap_offset,
+                            items: [
+                                {
+                                    el: self.searcher
+                                }
+                            ]
+
+
+                        }
+                    },
+                    {
+                        el: {
+                            type: "bi.center_adapt",
+                            cls: "style-left",
+                            items: [
+                                {
+                                    type: "bi.left",
+                                    hgap: c.hgap,
+                                    items: [
+                                        {
+                                            el: self.functionLabel
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    }
+                ], [
+                    {
+                        el: self.functiontree
+                    },
+                    {
+                        el: {
+                            type: "bi.absolute",
+                            cls: "style-inner",
+                            items: [
+                                {
+                                    el: self.desLabel,
+                                    left: c.hgap,
+                                    right: c.hgap,
+                                    top: c.hgap,
+                                    bottom: c.hgap
+                                }
+                            ]
+                        }
+                    }
+                ]
+            ]
+        });
+
+        self.functiontree.on(BI.FunctionTree.FUNCTION_INSERT, function (value) {
+            self.fireEvent(BI.FunctionPane.EVENT_INSET, value)
+        });
+
+        self.functiontree.on(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, function (v) {
+            self.desLabel.setText(v);
+        });
+
+        self.functiontree.on(BI.FunctionTree.EVENT_CHANGE, function (v) {
+            self.functionLabel.setText(v);
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.FUNCTION_INSERT, function (value) {
+            self.fireEvent(BI.FunctionPane.EVENT_INSET, value)
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, function (v) {
+            self.desLabel.setText(v);
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.EVENT_CHANGE, function (v) {
+            self.functionLabel.setText(v);
+        });
+
+    }
+
+});
+BI.FunctionPane.EVENT_INSET = "EVENT_INSET";
+$.shortcut("bi.function_pane", BI.FunctionPane);/**
+ * Created by roy on 16/1/21.
+ */
+BI.FunctionSearcherPane = BI.inherit(BI.SearcherView, {
+    _defaultConfig: function () {
+        var conf = BI.FunctionSearcherPane.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-function-searcher-pane"
+        })
+    },
+
+    _init: function () {
+        BI.FunctionSearcherPane.superclass._init.apply(this, arguments);
+    },
+
+    populate: function (searchResult, keyword) {
+        searchResult || (searchResult = []);
+        this.spliter.setVisible(false);
+        this.searcher.populate(searchResult, keyword);
+        this.searcher.expandAll();
+        this.searcher.doBehavior(keyword);
+    },
+
+
+});
+$.shortcut("bi.function_searcher_pane", BI.FunctionSearcherPane);BI.FormulaFieldTree = BI.inherit(BI.Widget, {
+    _const: {
+        leafGap: 40
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaFieldTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-field-tree",
+            chooseType: 0,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.FormulaFieldTree.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getFieldNum: function (map, fieldtype) {
+        if (BI.isNotNull(map[fieldtype])) {
+            return map[fieldtype].length
+        } else {
+            return 0
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options, c = this._const, self = this;
+        this.empty();
+        var map = {};
+        BI.each(items, function (i, typeItem) {
+            BI.each(typeItem, function (i, item) {
+                if (!map[item.fieldType]) {
+                    map[item.fieldType] = [];
+                }
+                map[item.fieldType].push(item);
+            })
+        });
+
+        var nodes = [{
+            id: BICst.COLUMN.NUMBER,
+            type: "bi.triangle_group_node",
+            text: BI.i18nText("BI-Formula_Numberic_Field") + "(" + self._getFieldNum(map,BICst.COLUMN.NUMBER) + ")",
+            value: BICst.COLUMN.NUMBER,
+            isParent: true,
+            open: items.length === 1
+        }];
+
+        if(items.length > 1){
+            nodes.push({
+                id: BICst.COLUMN.STRING,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Text_Field") + "(" + self._getFieldNum(map, BICst.COLUMN.STRING) + ")",
+                value: BICst.COLUMN.STRING,
+                isParent: true,
+                open: false
+            });
+        }
+
+        if(items.length > 2){
+            nodes.push({
+                id: BICst.COLUMN.DATE,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Time_Field") + "(" + self._getFieldNum(map, BICst.COLUMN.DATE) + ")",
+                value: BICst.COLUMN.DATE,
+                isParent: true,
+                open: false
+            });
+        }
+
+        BI.each(items, function(idx, typeItems){
+            BI.each(typeItems, function (i, item) {
+                nodes.push(BI.extend({
+                    id: BI.UUID(),
+                    pId: item.fieldType
+                }, item, {
+                    type: "bi.tree_text_leaf_item",
+                    cls: "tree-text-leaf-item-draggable",
+                    textAlign: "left",
+                    lgap: c.leafGap
+                }))
+            });
+        });
+        this.fieldtree = BI.createWidget({
+            type: "bi.level_tree",
+            element: this,
+            chooseType: o.chooseType,
+            expander: {
+                isDefaultInit: true
+            },
+            items: nodes
+        });
+        this.fieldtree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FormulaFieldTree.EVENT_CHANGE);
+            self.fieldtree.setValue();
+        })
+    },
+
+    getValue: function () {
+        return this.fieldtree.getValue();
+    },
+
+    setValue: function (v) {
+        this.fieldtree.setValue(v);
+    },
+    getAllLeaves: function () {
+        return this.fieldtree.getAllLeaves()
+    }
+});
+BI.FormulaFieldTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_field_tree", BI.FormulaFieldTree);/**
+ * Created by roy on 15/9/14.
+ */
+BI.FunctionTree = BI.inherit(BI.Widget, {
+    _const: {
+        leafGap: 10,
+        nodeTypes: [BICst.FUNCTION.MATH, BICst.FUNCTION.ARRAY, BICst.FUNCTION.DATE, BICst.FUNCTION.LOGIC, BICst.FUNCTION.OTHER, BICst.FUNCTION.TEXT]
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FunctionTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-function-tree",
+            chooseType: 0,
+            items: [],
+            redmark: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.FunctionTree.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getFieldNum: function (map, fieldtype) {
+        if (BI.isNotNull(map[fieldtype])) {
+            return map[fieldtype].length
+        } else {
+            return 0
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options, c = this._const, self = this;
+        this.empty();
+        var map = {};
+        o.items = items;
+        BI.each(items, function (i, item) {
+            if (!map[item.fieldType]) {
+                map[item.fieldType] = [];
+            }
+            map[item.fieldType].push(item);
+        });
+        this.nodes = [
+            {
+                id: BICst.FUNCTION.MATH,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Numberic_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.MATH) + ")",
+                value: BICst.FUNCTION.MATH,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.TEXT,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Text_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.TEXT) + ")",
+                value: BICst.FUNCTION.TEXT,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.DATE,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Time_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.DATE) + ")",
+                value: BICst.FUNCTION.DATE,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.ARRAY,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Array_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.ARRAY) + ")",
+                value: BICst.FUNCTION.ARRAY,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.LOGIC,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Logic_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.LOGIC) + ")",
+                value: BICst.FUNCTION.LOGIC,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.OTHER,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Other_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.OTHER) + ")",
+                value: BICst.FUNCTION.OTHER,
+                isParent: true,
+                open: false
+            }
+        ];
+        BI.each(items, function (i, item) {
+            self.nodes.push(BI.extend({
+                id: BI.UUID(),
+                pId: item.fieldType
+            }, item, {
+                type: "bi.button_text_tree_leaf_item",
+                textAlign: "left",
+                lgap: c.leafGap
+            }))
+        });
+        this.fieldtree = BI.createWidget({
+            type: "bi.level_tree",
+            element: this,
+            items: self.nodes,
+            el: {
+                behaviors: {
+                    "redmark": o.redmark
+                }
+            }
+        });
+
+        this.fieldtree.on(BI.Controller.EVENT_CHANGE, function (type, value) {
+            if (type === BI.Events.ADD) {
+                self.fireEvent(BI.FunctionTree.FUNCTION_INSERT, value);
+            }
+        });
+        this.fieldtree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FunctionTree.EVENT_CHANGE, self.getValue());
+            self.fireEvent(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, self._getDescription(self.getValue(), o.items))
+            self.fieldtree.setValue(self.getValue());
+        })
+    },
+
+    getValue: function () {
+        return this.fieldtree.getValue();
+    },
+
+    setValue: function (v) {
+        this.fieldtree.setValue(v);
+    },
+
+    doBehavior: function () {
+        this.fieldtree.doBehavior.apply(this.fieldtree, arguments)
+    },
+
+    getNodeByValue: function (v) {
+        return this.fieldtree.getNodeByValue(v)
+    },
+
+    setTriggerExpand: function (v) {
+        var node = this.fieldtree.getNodeById(v);
+        node.showView();
+    },
+
+    setTriggerCollapse: function (v) {
+        var node = this.fieldtree.getNodeById(v);
+        node.hideView();
+    },
+
+    expandAll: function () {
+        var self = this;
+        BI.each(self._const.nodeTypes, function (i, id) {
+            self.setTriggerExpand(id);
+        })
+    },
+
+    _getDescription: function (v, items) {
+        var description = "";
+        BI.each(items, function (i, item) {
+            if (item.value === v[0]) {
+                description = item.description;
+            }
+        });
+        return description
+    },
+
+    getAllLeaves: function () {
+        return this.fieldtree.getAllLeaves()
+    }
+});
+BI.FunctionTree.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FunctionTree.EVENT_DESCRIPTION_CHANGE = "EVENT_DESCRIPTION_CHANGE";
+BI.FunctionTree.FUNCTION_INSERT = "FUNCTION_INSERT";
+$.shortcut("bi.function_tree", BI.FunctionTree);/**
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonHref = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ImageButtonHref.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-image-button-href",
+            title: BI.i18nText("BI-Add_Href")
+        })
+    },
+
+    _init: function () {
+        BI.ImageButtonHref.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "img-href-font",
+            title: o.title,
+            height: 24,
+            width: 24
+        });
+
+        this.input = BI.createWidget({
+            type: "bi.clear_editor",
+            watermark: BI.i18nText("BI-Input_Href"),
+            width: 255,
+            height: 30
+        });
+        this.input.on(BI.ClearEditor.EVENT_CONFIRM, function () {
+            self.combo.hideView();
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            direction: "bottom,left",
+            adjustYOffset: 3,
+            el: this.trigger,
+            popup: {
+                el: this.input,
+                stopPropagation: false,
+                minWidth: 255
+            }
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.input.focus()
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () {
+            self.fireEvent(BI.ImageButtonHref.EVENT_CHANGE, arguments)
+        })
+    },
+
+    isSelected: function(){
+        return this.combo.isViewVisible();
+    },
+
+    showView: function(){
+        this.combo.showView();
+    },
+
+    hideView: function () {
+        this.combo.hideView();
+    },
+
+    getValue: function () {
+        return this.input.getValue();
+    },
+
+    setValue: function (url) {
+        this.input.setValue(url)
+    }
+});
+BI.ImageButtonHref.EVENT_CHANGE = "BI.ImageButtonHref.EVENT_CHANGE";
+$.shortcut("bi.image_button_href", BI.ImageButtonHref);/**
+ * 图片尺寸控件
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSizeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ImageButtonSizeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-image-button-size-combo",
+            title: BI.i18nText("BI-Image_Size")
+        })
+    },
+
+    _init: function () {
+        BI.ImageButtonSizeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "img-size-font",
+            title: o.title,
+            width: 24,
+            height: 24
+        });
+        this.sizeChooser = BI.createWidget({
+            type: "bi.image_button_size"
+        });
+        this.sizeChooser.on(BI.ImageButtonSize.EVENT_CHANGE, function(){
+            self.fireEvent(BI.ImageButtonSizeCombo.EVENT_CHANGE,arguments)
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustWidth: false,
+            direction: "top",
+            adjustYOffset: 3,
+            offsetStyle: "right",
+            el: this.trigger,
+            popup: {
+                el: this.sizeChooser,
+                stopPropagation: false
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.sizeChooser.setValue(v);
+    },
+
+    getValue: function () {
+        return this.sizeChooser.getValue();
+    }
+});
+BI.ImageButtonSizeCombo.EVENT_CHANGE = "ImageButtonSizeCombo.EVENT_CHANGE";
+$.shortcut("bi.image_button_size_combo", BI.ImageButtonSizeCombo);/**
+ * 单选框
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSize = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function(){
+        return BI.extend(BI.ImageButtonSize.superclass._defaultConfig.apply(this, arguments),{
+            baseCls: "bi-image-button-size",
+            width: 230,
+            height: 30
+        })
+    },
+
+    _init:function() {
+        BI.ImageButtonSize.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.sizeChooser = BI.createWidget({
+            type: "bi.button_group",
+            scrollable: false,
+            items: BI.createItems([{
+                text: BI.i18nText("BI-Original_Size"),
+                cls: "image-button-size-button-group",
+                width: 55,
+                selected: true,
+                value: BICst.IMAGE_RESIZE_MODE.ORIGINAL
+            },{
+                text: BI.i18nText("BI-Equal_Size_Adapt"),
+                cls: "image-button-size-button-group",
+                width: 67,
+                value: BICst.IMAGE_RESIZE_MODE.EQUAL
+            },{
+                text: BI.i18nText("BI-Widget_Size_Adapt"),
+                cls: "image-button-size-button-group",
+                width: 67,
+                value: BICst.IMAGE_RESIZE_MODE.STRETCH
+            }],{
+                type: "bi.image_button_size_radio"
+            }),
+            layouts: [{
+                type: "bi.left",
+                hgap: 5
+            }]
+        });
+
+        this.sizeChooser.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.sizeChooser.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.ImageButtonSize.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.sizeChooser],
+            hgap: 5
+        });
+        this.getValue()
+    },
+
+    getValue: function () {
+        return this.sizeChooser.getValue()[0]
+    },
+
+    setValue: function (v) {
+        this.sizeChooser.setValue(v)
+    }
+});
+BI.ImageButtonSize.EVENT_CHANGE = "BI.ImageButtonSize.EVENT_CHANGE";
+$.shortcut("bi.image_button_size" , BI.ImageButtonSize);/**
+ * 单选框
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSizeRadio = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function(){
+        return BI.extend(BI.ImageButtonSizeRadio.superclass._defaultConfig.apply(this, arguments),{
+            width: 65,
+            height: 30,
+            text: "",
+            selected: false
+        })
+    },
+
+    _init:function() {
+        BI.ImageButtonSizeRadio.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: o.selected
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            lgap: 5,
+            rgap: 0,
+            textHeight: o.height,
+            height: o.height,
+            text: o.text
+        });
+
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(!self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            element: this,
+            type: "bi.absolute",
+            items: [{
+                el: this.radio,
+                left: 0,
+                top: 8.5
+            },{
+                el: this.label,
+                left: 13
+            }]
+        });
+    },
+
+    doClick: function () {
+        BI.ImageButtonSizeRadio.superclass.doClick.apply(this, arguments);
+        this.radio.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.ImageButtonSizeRadio.superclass.setSelected.apply(this, arguments);
+        this.radio.setSelected(v);
+
+    }
+});
+$.shortcut("bi.image_button_size_radio" , BI.ImageButtonSizeRadio);/**
+ * 图片组件
+ * Created by GameJian on 2016/1/26.
+ */
+BI.UploadImage = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.UploadImage.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-upload-image"
+        })
+    },
+
+    _init: function () {
+        BI.UploadImage.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.label = BI.createWidget({
+            type: "bi.text_button",
+            trigger: "dblclick",
+            cls: "upload-image-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-DoubleClick_To_Upload_Image")
+        });
+
+        this.file = BI.createWidget({
+            type: "bi.multifile_editor",
+            accept: "*.jpg;*.png;*.gif;*.bmp;*.jpeg;",
+            maxSize: 1024 * 1024 * 100,
+            title: BI.i18nText("BI-Upload_Image")
+        });
+
+        this.img = BI.createWidget({
+            type: "bi.image_button",
+            invalid: true,
+            width: "100%",
+            height: "100%"
+        });
+
+        this.label.on(BI.TextButton.EVENT_CHANGE, function () {
+            if (self.isValid()) {
+                self.file.select();
+            }
+        });
+
+        this.file.on(BI.MultifileEditor.EVENT_CHANGE, function (data) {
+            this.upload();
+        });
+        //直接把图片保存到resource目录下面
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADED, function () {
+            var files = this.getValue();
+            var file = files[files.length - 1];
+            var attachId = file.attach_id, fileName = file.filename;
+            var imageId = attachId + "_" + fileName;
+            BI.requestAsync("fr_bi_base", "save_upload_image", {
+                attach_id: attachId
+            }, function (res) {
+                self.img.setValue(imageId);
+                self.img.setSrc(BI.UploadImage.getImageSrc(imageId));
+                self._check();
+                self._setSize("auto", "auto");
+                self.fireEvent(BI.UploadImage.EVENT_CHANGE, imageId);
+            })
+        });
+
+        this.uploadWrapper = BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "upload-image-icon-button img-upload-font",
+                    width: 24,
+                    height: 24
+                },
+                top: 0,
+                right: 0,
+                bottom: 0,
+                left: 0
+            }, {
+                el: this.file,
+                top: 0,
+                right: 0,
+                bottom: 0,
+                left: 0
+            }],
+            width: 24,
+            height: 24
+        });
+
+        this.del = BI.createWidget({
+            type: "bi.bubble_combo",
+            el: {
+                type: "bi.icon_button",
+                cls: "upload-image-icon-button img-shutdown-font",
+                title: BI.i18nText("BI-Basic_Delete"),
+                height: 24,
+                width: 24
+            },
+            popup: {
+                type: "bi.bubble_bar_popup_view",
+                buttons: [{
+                    value: BI.i18nText(BI.i18nText("BI-Basic_Sure")),
+                    handler: function () {
+                        self.fireEvent(BI.UploadImage.EVENT_DESTROY);
+                    }
+                }, {
+                    value: BI.i18nText("BI-Basic_Cancel"),
+                    level: "ignore",
+                    handler: function () {
+                        self.del.hideView();
+                    }
+                }],
+                el: {
+                    type: "bi.vertical_adapt",
+                    items: [{
+                        type: "bi.label",
+                        text: BI.i18nText("BI-Sure_Delete_Current_Component"),
+                        cls: "upload-image-delete-label",
+                        textAlign: "left",
+                        width: 300
+                    }],
+                    width: 300,
+                    height: 100,
+                    hgap: 20
+                },
+                maxHeight: 140,
+                minWidth: 340
+            },
+            invisible: true,
+            stopPropagation: true
+        });
+
+        this.size = BI.createWidget({
+            type: "bi.image_button_size_combo",
+            cls: "upload-image-icon-button"
+        });
+
+        this.size.on(BI.ImageButtonSizeCombo.EVENT_CHANGE, function () {
+            self._sizeChange(self.size.getValue());
+            self.fireEvent(BI.UploadImage.EVENT_CHANGE, arguments)
+        });
+
+        this.href = BI.createWidget({
+            type: "bi.image_button_href",
+            cls: "upload-image-icon-button"
+        });
+
+        this.href.on(BI.ImageButtonHref.EVENT_CHANGE, function () {
+            if (BI.isNotEmptyString(self.href.getValue())) {
+                self.img.setValid(true)
+            } else {
+                self.img.setValid(false)
+            }
+            self.fireEvent(BI.UploadImage.EVENT_CHANGE, arguments)
+        });
+
+        this.img.on(BI.ImageButton.EVENT_CHANGE, function () {
+            window.open(BI.Func.formatAddress(self.href.getValue()));
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    scrollable: false,
+                    items: [{
+                        el: this.img
+                    }]
+                },
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.label,
+                left: 10,
+                right: 10,
+                top: 10,
+                bottom: 10
+            }, {
+                el: this.del,
+                right: 4,
+                top: 8
+            }, {
+                el: this.href,
+                right: 36,
+                top: 8
+            }, {
+                el: this.size,
+                right: 68,
+                top: 8
+            }, {
+                el: this.uploadWrapper,
+                right: 100,
+                top: 8
+            }]
+        });
+
+        this.setToolbarVisible(false);
+        this.img.invisible();
+    },
+
+    _check: function () {
+        var f = BI.isNotEmptyString(this.img.getValue());
+        this.label.setVisible(!f);
+        this.img.visible(f);
+    },
+
+    _setSize: function (w, h) {
+        this.img.setImageWidth(w);
+        this.img.setImageHeight(h)
+    },
+
+    _sizeChange: function (size) {
+        var self = this, o = this.options;
+        switch (size) {
+            case BICst.IMAGE_RESIZE_MODE.ORIGINAL:
+                self._setSize("auto", "auto");
+                break;
+            case BICst.IMAGE_RESIZE_MODE.EQUAL:
+                self._setSize("auto", "auto");
+                var width = this.img.getImageWidth(), height = this.img.getImageHeight();
+                var W = this.element.width(), H = this.element.height();
+                if (W / H > width / height) {
+                    self._setSize("auto", "100%");
+                } else {
+                    self._setSize("100%", "auto");
+                }
+                break;
+            case BICst.IMAGE_RESIZE_MODE.STRETCH:
+                self._setSize("100%", "100%");
+                break;
+            default :
+                self._setSize("auto", "auto");
+        }
+    },
+
+    setToolbarVisible: function (v) {
+        this.uploadWrapper.setVisible(v);
+        this.size.setVisible(v);
+        this.href.setVisible(v);
+        this.del.setVisible(v);
+    },
+
+    getValue: function () {
+        return {href: this.href.getValue(), size: this.size.getValue(), src: this.img.getValue()}
+    },
+
+    setValue: function (v) {
+        var self = this;
+        v || (v = {});
+        if (BI.isNotEmptyString(v.href)) {
+            self.img.setValid(true)
+        }
+        this.href.setValue(v.href);
+        this.size.setValue(v.size);
+        this.img.setValue(v.src);
+        if (BI.isNotEmptyString(v.src)) {
+            this.img.setSrc(BI.UploadImage.getImageSrc(v.src));
+        }
+        this._check();
+        this._sizeChange(v.size)
+    },
+
+    resize: function () {
+        this._sizeChange(this.size.getValue());
+    }
+});
+
+BI.extend(BI.UploadImage, {
+    getImageSrc: function (src) {
+        return FR.servletURL + "?op=fr_bi&cmd=get_uploaded_image&image_id=" + src;
+    }
+});
+
+BI.UploadImage.EVENT_DESTROY = "EVENT_DESTROY";
+BI.UploadImage.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.upload_image", BI.UploadImage);/**
+ * 交互行为布局
+ *
+ *
+ * Created by GUY on 2016/7/23.
+ * @class BI.InteractiveArrangement
+ * @extends BI.Widget
+ */
+BI.InteractiveArrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.InteractiveArrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-interactive-arrangement",
+            resizable: true,
+            isNeedReLayout: true,
+            isNeedResizeContainer: true,
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.InteractiveArrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.adaptive_arrangement",
+            element: this,
+            resizable: o.resizable,
+            isNeedReLayout: o.isNeedReLayout,
+            isNeedResizeContainer: o.isNeedResizeContainer,
+            layoutType: o.layoutType,
+            items: o.items
+        });
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_RESIZE, function () {
+            self.fireEvent(BI.InteractiveArrangement.EVENT_RESIZE, arguments);
+        });
+
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, function (id, size) {
+            var p = self._getRegionClientPosition(id);
+            self.draw({
+                left: p.left,
+                top: p.top
+            }, size, id);
+        });
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, function (id, size) {
+            self.stopDraw();
+            self.setRegionSize(id, size);
+        });
+
+        this.tags = [];
+
+    },
+
+    _isEqual: function (num1, num2) {
+        return this.arrangement._isEqual(num1, num2);
+    },
+
+    _getScrollOffset: function () {
+        return this.arrangement._getScrollOffset();
+    },
+
+    _positionAt: function (position, regions) {
+        var self = this;
+        regions = regions || this.getAllRegions();
+        var left = [], center = [], right = [], top = [], middle = [], bottom = [];
+        BI.each(regions, function (i, region) {
+            var client = self._getRegionClientPosition(region.id);
+            if (Math.abs(client.left - position.left) <= 3) {
+                left.push(region);
+            }
+            if (Math.abs(client.left + client.width / 2 - position.left) <= 3) {
+                center.push(region);
+            }
+            if (Math.abs(client.left + client.width - position.left) <= 3) {
+                right.push(region);
+            }
+            if (Math.abs(client.top - position.top) <= 3) {
+                top.push(region);
+            }
+            if (Math.abs(client.top + client.height / 2 - position.top) <= 3) {
+                middle.push(region);
+            }
+            if (Math.abs(client.top + client.height - position.top) <= 3) {
+                bottom.push(region);
+            }
+        });
+        return {
+            left: left,
+            center: center,
+            right: right,
+            top: top,
+            middle: middle,
+            bottom: bottom
+        }
+    },
+
+    _getRegionClientPosition: function (name) {
+        var region = this.getRegionByName(name);
+        var offset = this.arrangement._getScrollOffset();
+        return {
+            top: region.top - offset.top,
+            left: region.left - offset.left,
+            width: region.width,
+            height: region.height,
+            id: region.id
+        }
+    },
+
+    _vAlign: function (position, regions) {
+        var self = this;
+        var vs = this._positionAt(position, regions);
+        var positions = [];
+        var l;
+        if (vs.left.length > 0) {
+            l = this._getRegionClientPosition(vs.left[0].id).left;
+        } else if (vs.right.length > 0) {
+            var temp = this._getRegionClientPosition(vs.right[0].id);
+            l = temp.left + temp.width;
+        }
+        var rs = vs.left.concat(vs.right);
+        BI.each(rs, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.left, l) || self._isEqual(p.left + p.width, l)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: l
+                };
+                positions.push({
+                    id: region.id,
+                    start: topPoint,
+                    end: {
+                        left: l,
+                        top: position.top
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _leftAlign: function (position, size, regions) {
+        var self = this;
+        return this._vAlign({
+            left: position.left,
+            top: position.top + size.height / 2
+        }, regions);
+    },
+
+    _rightAlign: function (position, size, regions) {
+        var self = this;
+        return this._vAlign({
+            left: position.left + size.width,
+            top: position.top + size.height / 2
+        }, regions);
+    },
+
+    _hAlign: function (position, regions) {
+        var self = this;
+        var hs = this._positionAt(position, regions);
+        var positions = [];
+        var t;
+        if (hs.top.length > 0) {
+            var temp = this._getRegionClientPosition(hs.top[0].id);
+            t = temp.top;
+        } else if (hs.bottom.length > 0) {
+            var temp = this._getRegionClientPosition(hs.bottom[0].id);
+            t = temp.top + temp.height;
+        }
+        var rs = hs.top.concat(hs.bottom);
+        BI.each(rs, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.top, t) || self._isEqual(p.top + p.height, t)) {
+                var leftPoint = {
+                    top: t,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: leftPoint,
+                    end: {
+                        left: position.left,
+                        top: t
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _topAlign: function (position, size, regions) {
+        var self = this;
+        return this._hAlign({
+            left: position.left + size.width / 2,
+            top: position.top
+        }, regions);
+    },
+
+    _bottomAlign: function (position, size, regions) {
+        var self = this;
+        return this._hAlign({
+            left: position.left + size.width / 2,
+            top: position.top + size.height
+        }, regions);
+    },
+
+    _centerAlign: function (position, size, regions) {
+        var self = this;
+        var cs = this._positionAt({
+            left: position.left + size.width / 2,
+            top: position.top + size.height / 2
+        }, regions);
+        var positions = [];
+        var l;
+        if (cs.center.length > 0) {
+            var temp = this._getRegionClientPosition(cs.center[0].id);
+            l = temp.left + temp.width / 2;
+        }
+        BI.each(cs.center, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.left + p.width / 2, l)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: topPoint,
+                    end: {
+                        left: l,
+                        top: position.top + size.height / 2
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _middleAlign: function (position, size, regions) {
+        var self = this;
+        var cs = this._positionAt({
+            left: position.left + size.width / 2,
+            top: position.top + size.height / 2
+        }, regions);
+        var positions = [];
+        var t;
+        if (cs.middle.length > 0) {
+            var temp = this._getRegionClientPosition(cs.middle[0].id);
+            t = temp.top + temp.height / 2;
+        }
+        BI.each(cs.middle, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.top + p.height / 2, t)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: topPoint,
+                    end: {
+                        left: position.left + size.width / 2,
+                        top: t
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+
+    _drawOneTag: function (start, end) {
+        var s = BI.createWidget({
+            type: "bi.icon_button",
+            //invisible: true,
+            width: 13,
+            height: 13,
+            cls: "drag-tag-font interactive-arrangement-dragtag-icon"
+        });
+        var e = BI.createWidget({
+            type: "bi.icon_button",
+            //invisible: true,
+            width: 13,
+            height: 13,
+            cls: "drag-tag-font interactive-arrangement-dragtag-icon"
+        });
+        if (this._isEqual(start.left, end.left)) {
+            var line = BI.createWidget({
+                type: "bi.layout",
+                //invisible: true,
+                cls: "interactive-arrangement-dragtag-line",
+                width: 1,
+                height: Math.abs(start.top - end.top)
+            });
+        } else {
+            var line = BI.createWidget({
+                type: "bi.layout",
+                //invisible: true,
+                cls: "interactive-arrangement-dragtag-line",
+                height: 1,
+                width: Math.abs(start.left - end.left)
+            });
+        }
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: s,
+                left: start.left - 6,
+                top: start.top - 7
+            }, {
+                el: e,
+                left: end.left - 6,
+                top: end.top - 7
+            }, {
+                el: line,
+                left: Math.min(start.left, end.left),
+                top: Math.min(start.top, end.top)
+            }]
+        });
+        this.tags.push(s);
+        this.tags.push(e);
+        this.tags.push(line);
+    },
+
+    stopDraw: function () {
+        BI.each(this.tags, function (i, w) {
+            w.destroy();
+        });
+        this.tags = [];
+    },
+
+    _getRegionExcept: function (name, regions) {
+        var other = [];
+        BI.each(regions || this.getAllRegions(), function (i, region) {
+            if (!(name && region.id === name)) {
+                other.push(region);
+            }
+        });
+        return other;
+    },
+
+    getClientWidth: function () {
+        return this.arrangement.getClientWidth();
+    },
+
+    getClientHeight: function () {
+        return this.arrangement.getClientHeight();
+    },
+
+    getPosition: function (name, position, size) {
+        var regions = this.getAllRegions();
+        var me;
+        if (name) {
+            me = this._getRegionClientPosition(name);
+        }
+        var other = this._getRegionExcept(name, regions);
+        position = position || {
+                left: me.left,
+                top: me.top
+            };
+        size = size || {
+                width: me.width,
+                height: me.height
+            };
+        var left = this._leftAlign(position, size, other);
+        var right = this._rightAlign(position, size, other);
+        var top = this._topAlign(position, size, other, other);
+        var bottom = this._bottomAlign(position, size, other);
+        var center = this._centerAlign(position, size, other);
+        var middle = this._middleAlign(position, size, other);
+
+        BI.each(center, function (i, pos) {
+            position.left = pos.end.left - size.width / 2;
+        });
+        BI.each(right, function (i, pos) {
+            position.left = pos.end.left - size.width;
+        });
+        BI.each(left, function (i, pos) {
+            position.left = pos.end.left;
+        });
+        BI.each(middle, function (i, pos) {
+            position.top = pos.end.top - size.height / 2;
+        });
+        BI.each(bottom, function (i, pos) {
+            position.top = pos.end.top - size.height;
+        });
+        BI.each(top, function (i, pos) {
+            position.top = pos.end.top;
+        });
+        return position;
+    },
+
+    //position不动 变size
+    getSize: function (name, position, size) {
+        var regions = this.getAllRegions();
+        var me;
+        if (name) {
+            me = this._getRegionClientPosition(name);
+        }
+        var other = this._getRegionExcept(name, regions);
+        position = position || {
+                left: me.left,
+                top: me.top
+            };
+        size = size || {
+                width: me.width,
+                height: me.height
+            };
+        var left = this._leftAlign(position, size, other);
+        var right = this._rightAlign(position, size, other);
+        var top = this._topAlign(position, size, other, other);
+        var bottom = this._bottomAlign(position, size, other);
+        var center = this._centerAlign(position, size, other);
+        var middle = this._middleAlign(position, size, other);
+
+        BI.each(center, function (i, pos) {
+            size.width = (pos.end.left - position.left) * 2;
+        });
+        BI.each(right, function (i, pos) {
+            size.width = pos.end.left - position.left;
+        });
+        BI.each(left, function (i, pos) {
+        });
+        BI.each(middle, function (i, pos) {
+            size.height = (pos.end.top - position.top) * 2;
+        });
+        BI.each(bottom, function (i, pos) {
+            size.height = pos.end.top - position.top;
+        });
+        BI.each(top, function (i, pos) {
+        });
+        return size;
+    },
+
+    draw: function (position, size, name) {
+        var self = this;
+        this.stopDraw();
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var other = this._getRegionExcept(name);
+                var left = this._leftAlign(position, size, other);
+                var right = this._rightAlign(position, size, other);
+                var top = this._topAlign(position, size, other);
+                var bottom = this._bottomAlign(position, size, other);
+                var center = this._centerAlign(position, size, other);
+                var middle = this._middleAlign(position, size, other);
+
+                BI.each(center, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(right, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(left, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(middle, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(bottom, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(top, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        return this.arrangement.getDirectRelativeRegions(name, direction);
+    },
+
+    addRegion: function (region, position) {
+        this.stopDraw();
+        return this.arrangement.addRegion(region, position);
+    },
+
+    deleteRegion: function (name) {
+        return this.arrangement.deleteRegion(name);
+    },
+
+    setRegionSize: function (name, size) {
+        size = this.getSize(name, null, size);
+        return this.arrangement.setRegionSize(name, size);
+    },
+
+    setPosition: function (position, size) {
+        var self = this;
+        this.stopDraw();
+        if (position.left > 0 && position.top > 0) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    position = this.getPosition(null, position, size);
+                    this.draw(position, size);
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        var at = this.arrangement.setPosition(position, size);
+        return at;
+    },
+
+    setRegionPosition: function (name, position) {
+        if (position.left > 0 && position.top > 0) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    position = this.getPosition(name, position);
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        return this.arrangement.setRegionPosition(name, position);
+    },
+
+    zoom: function (ratio) {
+        this.arrangement.zoom(ratio);
+    },
+
+    resize: function () {
+        return this.arrangement.resize();
+    },
+
+    relayout: function () {
+        return this.arrangement.relayout();
+    },
+
+    setLayoutType: function (type) {
+        this.arrangement.setLayoutType(type);
+    },
+
+    getLayoutType: function () {
+        return this.arrangement.getLayoutType();
+    },
+
+    getLayoutRatio: function () {
+        return this.arrangement.getLayoutRatio();
+    },
+
+    getHelper: function () {
+        return this.arrangement.getHelper();
+    },
+
+    getRegionByName: function (name) {
+        return this.arrangement.getRegionByName(name);
+    },
+
+    getAllRegions: function () {
+        return this.arrangement.getAllRegions();
+    },
+
+    revoke: function () {
+        return this.arrangement.revoke();
+    },
+
+    populate: function (items) {
+        var self = this;
+        this.arrangement.populate(items);
+    }
+});
+BI.InteractiveArrangement.EVENT_RESIZE = "InteractiveArrangement.EVENT_RESIZE";
+$.shortcut('bi.interactive_arrangement', BI.InteractiveArrangement);/**
+ * Created by zcf on 2016/9/26.
+ */
+BI.IntervalSlider = BI.inherit(BI.Widget, {
+    _constant: {
+        EDITOR_WIDTH: 90,
+        EDITOR_HEIGHT: 30,
+        HEIGHT: 28,
+        SLIDER_WIDTH_HALF: 15,
+        SLIDER_WIDTH: 30,
+        SLIDER_HEIGHT: 30,
+        TRACK_HEIGHT: 24
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.IntervalSlider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider bi-slider-track"
+        })
+    },
+
+    _init: function () {
+        BI.IntervalSlider.superclass._init.apply(this, arguments);
+
+        var self = this;
+        var c = this._constant;
+        this.enable = false;
+        this.valueOne = "";
+        this.valueTwo = "";
+        this.calculation = new BI.AccurateCalculationModel();
+
+        this.backgroundTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "background-track",
+            height: c.TRACK_HEIGHT
+        });
+        this.grayTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "gray-track",
+            height: 8
+        });
+        this.blueTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "blue-track",
+            height: 8
+        });
+        this.track = this._createTrackWrapper();
+
+        this.labelOne = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            allowBlank: false,
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.labelOne.on(BI.Editor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));//分成1000份
+            self._setLabelOnePosition(significantPercent);
+            self._setSliderOnePosition(significantPercent);
+            self._setBlueTrack();
+            self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+        });
+
+        this.labelTwo = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            allowBlank: false,
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.labelTwo.on(BI.Editor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));
+            self._setLabelTwoPosition(significantPercent);
+            self._setSliderTwoPosition(significantPercent);
+            self._setBlueTrack();
+            self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+        });
+
+        this.sliderOne = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.sliderOne.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setLabelOnePosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.labelOne.setValue(v);
+                self.valueOne = v;
+                self._setBlueTrack();
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderOnePosition(significantPercent);
+                self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+            }
+        });
+
+        this.sliderTwo = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.sliderTwo.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setLabelTwoPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.labelTwo.setValue(v);
+                self.valueTwo = v;
+                self._setBlueTrack();
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderTwoPosition(significantPercent);
+                self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+            }
+        });
+        this._setVisible(false);
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.track,
+                            width: "100%",
+                            height: c.TRACK_HEIGHT
+                        }]
+                    }],
+                    hgap: 7,
+                    height: c.TRACK_HEIGHT
+                },
+                top: 33,
+                left: 0,
+                width: "100%"
+            },
+                this._createLabelWrapper(),
+                this._createSliderWrapper()
+            ]
+        })
+    },
+
+    _createLabelWrapper: function () {
+        var c = this._constant;
+        return {
+            el: {
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.labelOne,
+                        top: 0,
+                        left: "0%"
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.labelTwo,
+                        top: 0,
+                        left: "100%"
+                    }]
+                }],
+                rgap: c.EDITOR_WIDTH,
+                height: 90
+            },
+            top: 0,
+            left: 0,
+            width: "100%"
+        }
+    },
+
+    _createSliderWrapper: function () {
+        var c = this._constant;
+        return {
+            el: {
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.sliderOne,
+                        top: 0,
+                        left: "0%"
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.sliderTwo,
+                        top: 0,
+                        left: "100%"
+                    }]
+                }],
+                hgap: c.SLIDER_WIDTH_HALF,
+                height: c.SLIDER_HEIGHT
+            },
+            top: 30,
+            left: 0,
+            width: "100%"
+        }
+    },
+
+    _createTrackWrapper: function () {
+        return BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.backgroundTrack,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.grayTrack,
+                            top: 0,
+                            left: 0,
+                            width: "100%"
+                        }, {
+                            el: this.blueTrack,
+                            top: 0,
+                            left: 0,
+                            width: "0%"
+                        }]
+                    }],
+                    hgap: 8,
+                    height: 8
+                },
+                top: 8,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _checkValidation: function (v) {
+        return !(BI.isNull(v) || v < this.min || v > this.max)
+    },
+
+    _checkOverlap: function () {
+        var labelOneLeft = this.labelOne.element[0].offsetLeft;
+        var labelTwoLeft = this.labelTwo.element[0].offsetLeft;
+        if (labelOneLeft <= labelTwoLeft) {
+            if ((labelTwoLeft - labelOneLeft) < 90) {
+                this.labelTwo.element.css({"top": 60});
+            } else {
+                this.labelTwo.element.css({"top": 0});
+            }
+        } else {
+            if ((labelOneLeft - labelTwoLeft) < 90) {
+                this.labelTwo.element.css({"top": 60});
+            } else {
+                this.labelTwo.element.css({"top": 0});
+            }
+        }
+    },
+
+    _setLabelOnePosition: function (percent) {
+        this.labelOne.element.css({"left": percent + "%"});
+        this._checkOverlap();
+    },
+
+    _setLabelTwoPosition: function (percent) {
+        this.labelTwo.element.css({"left": percent + "%"});
+        this._checkOverlap();
+    },
+
+    _setSliderOnePosition: function (percent) {
+        this.sliderOne.element.css({"left": percent + "%"});
+    },
+
+    _setSliderTwoPosition: function (percent) {
+        this.sliderTwo.element.css({"left": percent + "%"});
+    },
+
+    _setBlueTrackLeft: function (percent) {
+        this.blueTrack.element.css({"left": percent + "%"});
+    },
+
+    _setBlueTrackWidth: function (percent) {
+        this.blueTrack.element.css({"width": percent + "%"});
+    },
+
+    _setBlueTrack: function () {
+        var percentOne = this._getPercentByValue(this.labelOne.getValue());
+        var percentTwo = this._getPercentByValue(this.labelTwo.getValue());
+        if (percentOne <= percentTwo) {
+            this._setBlueTrackLeft(percentOne);
+            this._setBlueTrackWidth(percentTwo - percentOne);
+        } else {
+            this._setBlueTrackLeft(percentTwo);
+            this._setBlueTrackWidth(percentOne - percentTwo);
+        }
+    },
+
+    _setAllPosition: function (one, two) {
+        this._setSliderOnePosition(one);
+        this._setLabelOnePosition(one);
+        this._setSliderTwoPosition(two);
+        this._setLabelTwoPosition(two);
+        this._setBlueTrack();
+    },
+
+    _setVisible: function (visible) {
+        this.sliderOne.setVisible(visible);
+        this.sliderTwo.setVisible(visible);
+        this.labelOne.setVisible(visible);
+        this.labelTwo.setVisible(visible);
+    },
+
+    _setErrorText: function () {
+        var errorText = BI.i18nText("BI-Please_Enter") + this.min + "-" + this.max + BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Basic_Number");
+        this.labelOne.setErrorText(errorText);
+        this.labelTwo.setErrorText(errorText);
+    },
+
+    _getGrayTrackLength: function () {
+        return this.grayTrack.element[0].scrollWidth
+    },
+
+    _getValueByPercent: function (percent) {//return (((max-min)*percent)/100+min)
+        var sub = this.calculation.accurateSubtraction(this.max, this.min);
+        var mul = this.calculation.accurateMultiplication(sub, percent);
+        var div = this.calculation.accurateDivisionTenExponent(mul, 2);
+        return this.calculation.accurateAddition(div, this.min);
+    },
+
+    _getPercentByValue: function (v) {
+        return (v - this.min) * 100 / (this.max - this.min);
+    },
+
+    _setDraggableEnable: function (enable) {
+        if (enable) {
+            this.sliderOne.element.draggable("enable");
+            this.sliderTwo.element.draggable("enable")
+        } else {
+            this.sliderOne.element.draggable("disable");
+            this.sliderTwo.element.draggable("disable")
+        }
+    },
+
+    getValue: function () {
+        if (this.valueOne <= this.valueTwo) {
+            return {min: this.valueOne, max: this.valueTwo}
+        } else {
+            return {min: this.valueTwo, max: this.valueOne}
+        }
+    },
+
+    setMinAndMax: function (v) {
+        var minNumber = BI.parseFloat(v.min);
+        var maxNumber = BI.parseFloat(v.max);
+        if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber >= minNumber )) {
+            this.min = minNumber;
+            this.max = maxNumber;
+            this.valueOne = minNumber;
+            this.valueTwo = maxNumber;
+            this._setDraggableEnable(true);
+        }
+        if (maxNumber === minNumber) {
+            this._setDraggableEnable(false);
+        }
+    },
+
+    setValue: function (v) {
+        var valueOne = BI.parseFloat(v.min);
+        var valueTwo = BI.parseFloat(v.max);
+        if (!isNaN(valueOne) && !isNaN(valueTwo)) {
+            if (this._checkValidation(valueOne)) {
+                this.valueOne = valueOne;
+            }
+            if (this._checkValidation(valueTwo)) {
+                this.valueTwo = valueTwo;
+            }
+            if (valueOne < this.min) {
+                this.valueOne = this.min;
+            }
+            if (valueTwo > this.max) {
+                this.valueTwo = this.max;
+            }
+        }
+    },
+
+    reset: function () {
+        this._setVisible(false);
+        this.enable = false;
+        this.valueOne = "";
+        this.valueTwo = "";
+        this.min = NaN;
+        this.max = NaN;
+        this._setBlueTrackWidth(0);
+    },
+
+    populate: function () {
+        if (!isNaN(this.min) && !isNaN(this.max)) {
+            this.enable = true;
+            this._setVisible(true);
+            this._setErrorText();
+            if ((BI.isNumeric(this.valueOne) || BI.isNotEmptyString(this.valueOne)) && (BI.isNumeric(this.valueTwo) || BI.isNotEmptyString(this.valueTwo))) {
+                this.labelOne.setValue(this.valueOne);
+                this.labelTwo.setValue(this.valueTwo);
+                this._setAllPosition(this._getPercentByValue(this.valueOne), this._getPercentByValue(this.valueTwo));
+            } else {
+                this.labelOne.setValue(this.min);
+                this.labelTwo.setValue(this.max);
+                this._setAllPosition(0, 100)
+            }
+        }
+    }
+});
+BI.IntervalSlider.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.interval_slider", BI.IntervalSlider);/**
+ * Created by zcf on 2017/3/1.
+ * 万恶的IEEE-754
+ * 使用字符串精确计算含小数加法、减法、乘法和10的指数倍除法,支持负数
+ */
+BI.AccurateCalculationModel = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.AccurateCalculationModel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: ""
+        })
+    },
+
+    _init: function () {
+        BI.AccurateCalculationModel.superclass._init.apply(this, arguments);
+    },
+
+    _getMagnitude: function (n) {
+        var magnitude = "1";
+        for (var i = 0; i < n; i++) {
+            magnitude += "0";
+        }
+        return BI.parseInt(magnitude);
+    },
+
+    _formatDecimal: function (stringNumber1, stringNumber2) {
+        if (stringNumber1.numDecimalLength === stringNumber2.numDecimalLength) {
+            return;
+        }
+        var magnitudeDiff = stringNumber1.numDecimalLength - stringNumber2.numDecimalLength;
+        if (magnitudeDiff > 0) {
+            var needAddZero = stringNumber2
+        } else {
+            var needAddZero = stringNumber1;
+            magnitudeDiff = (0 - magnitudeDiff);
+        }
+        for (var i = 0; i < magnitudeDiff; i++) {
+            if (needAddZero.numDecimal === "0" && i === 0) {
+                continue
+            }
+            needAddZero.numDecimal += "0"
+        }
+    },
+
+    _stringNumberFactory: function (num) {
+        var strNum = num.toString();
+        var numStrArray = strNum.split(".");
+        var numInteger = numStrArray[0];
+        if (numStrArray.length === 1) {
+            var numDecimal = "0";
+            var numDecimalLength = 0;
+        } else {
+            var numDecimal = numStrArray[1];
+            var numDecimalLength = numStrArray[1].length;
+        }
+        return {
+            "numInteger": numInteger,
+            "numDecimal": numDecimal,
+            "numDecimalLength": numDecimalLength
+        }
+    },
+
+    _accurateSubtraction: function (num1, num2) {//num1-num2 && num1>num2
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) - BI.parseInt(stringNumber2.numInteger);
+        //小数部分
+        this._formatDecimal(stringNumber1, stringNumber2);
+        var decimalMaxLength = getDecimalMaxLength(stringNumber1, stringNumber2);
+
+        if (BI.parseInt(stringNumber1.numDecimal) >= BI.parseInt(stringNumber2.numDecimal)) {
+            var decimalResultTemp = (BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
+            var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
+        } else {//否则借位
+            integerResult--;
+            var borrow = this._getMagnitude(decimalMaxLength);
+            var decimalResultTemp = (borrow + BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
+            var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
+        }
+        var result = integerResult + "." + decimalResult;
+        return BI.parseFloat(result);
+
+        function getDecimalMaxLength(num1, num2) {
+            if (num1.numDecimal.length >= num2.numDecimal.length) {
+                return num1.numDecimal.length
+            }
+            return num2.numDecimal.length
+        }
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    _accurateAddition: function (num1, num2) {//加法结合律
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) + BI.parseInt(stringNumber2.numInteger);
+        //小数部分
+        this._formatDecimal(stringNumber1, stringNumber2);
+
+        var decimalResult = (BI.parseInt(stringNumber1.numDecimal) + BI.parseInt(stringNumber2.numDecimal)).toString();
+
+        if (decimalResult !== "0") {
+            if (decimalResult.length <= stringNumber1.numDecimal.length) {
+                decimalResult = addZero(decimalResult, stringNumber1.numDecimal.length)
+            } else {
+                integerResult++;//进一
+                decimalResult = decimalResult.slice(1);
+            }
+        }
+        var result = integerResult + "." + decimalResult;
+        return BI.parseFloat(result);
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    _accurateMultiplication: function (num1, num2) {//乘法分配律
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numInteger);
+        //num1的小数和num2的整数
+        var dec1Int2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numInteger), stringNumber1.numDecimalLength);
+        //num1的整数和num2的小数
+        var int1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numDecimal), stringNumber2.numDecimalLength);
+        //小数*小数
+        var dec1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numDecimal), (stringNumber1.numDecimalLength + stringNumber2.numDecimalLength));
+
+        return this._accurateAddition(this._accurateAddition(this._accurateAddition(integerResult, dec1Int2), int1dec2), dec1dec2);
+    },
+
+    _accurateDivisionTenExponent: function (num, n) {// num/10^n && n>0
+        var stringNumber = this._stringNumberFactory(num);
+        if (stringNumber.numInteger.length > n) {
+            var integerResult = stringNumber.numInteger.slice(0, (stringNumber.numInteger.length - n));
+            var partDecimalResult = stringNumber.numInteger.slice(-n);
+        } else {
+            var integerResult = "0";
+            var partDecimalResult = addZero(stringNumber.numInteger, n);
+        }
+        var result = integerResult + "." + partDecimalResult + stringNumber.numDecimal;
+        return BI.parseFloat(result);
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    accurateSubtraction: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            if (num1 >= num2) {
+                return this._accurateSubtraction(num1, num2)
+            }
+            return this._accurateSubtraction(num2, num1)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return this._accurateAddition(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return -this._accurateAddition(-num1, num2)
+        }
+        if (num1 < 0 && num2 < 0) {
+            if (num1 >= num2) {
+                return this._accurateSubtraction(-num2, -num1)
+            }
+            return this._accurateSubtraction(-num1, -num2)
+        }
+    },
+
+    accurateAddition: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            return this._accurateAddition(num1, num2)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return this.accurateSubtraction(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return this.accurateSubtraction(num2, -num1)
+        }
+        if (num1 < 0 && num2 < 0) {
+            return -this._accurateAddition(-num1, -num2)
+        }
+    },
+
+    accurateMultiplication: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            return this._accurateMultiplication(num1, num2)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return -this._accurateMultiplication(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return -this._accurateMultiplication(-num1, num2)
+        }
+        if (num1 < 0 && num2 < 0) {
+            return this._accurateMultiplication(-num1, -num2)
+        }
+    },
+
+    accurateDivisionTenExponent: function (num1, n) {
+        if (num1 >= 0) {
+            return this._accurateDivisionTenExponent(num1, n);
+        }
+        return -this._accurateDivisionTenExponent(-num1, n);
+    }
+});/**
+ * Created by fay on 2016/9/14.
+ */
+BI.ListLabelItemGroup = BI.inherit(BI.ButtonGroup, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ListLabelItemGroup.superclass._defaultConfig.apply(this, arguments), {
+            chooseType: BI.Selection.Multi
+        });
+    },
+
+    _init: function () {
+        BI.ListLabelItemGroup.superclass._init.apply(this, arguments);
+        this.otherValues = [];
+        if (BI.isEmptyArray(this.getValue())) {
+            BI.each(this.buttons, function (idx, button) {
+                if (button.getValue() === BICst.LIST_LABEL_TYPE.ALL) {
+                    button.setSelected(true);
+                }
+            });
+        }
+        this._checkBtnStyle();
+    },
+
+    _createBtns: function (items) {
+        var o = this.options;
+        return BI.createWidgets(BI.createItems(items, {
+            type: "bi.text_button",
+            cls: "list-label-button"
+        }));
+    },
+
+
+    _btnsCreator: function (items) {
+        var self = this, args = Array.prototype.slice.call(arguments), o = this.options;
+        var buttons = this._createBtns(items);
+        args[0] = buttons;
+
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    switch (o.chooseType) {
+                        case BI.ButtonGroup.CHOOSE_TYPE_MULTI:
+                            if (btn.getValue() === BICst.LIST_LABEL_TYPE.ALL) {
+                                self.setValue([BICst.LIST_LABEL_TYPE.ALL]);
+                            } else {
+                                self._checkBtnState();
+                            }
+                            self._checkBtnStyle();
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                            self.setValue(btn.getValue());
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_NONE:
+                            self.setValue([]);
+                            break;
+                    }
+                    self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            btn.on(BI.Events.DESTROY, function () {
+                BI.remove(self.buttons, btn);
+            });
+        });
+
+        return buttons;
+    },
+
+    _checkBtnState: function () {
+        if (BI.isEmptyArray(this.getValue()) && BI.isEmptyArray(this.otherValues)) {
+            this.buttons[0].setSelected(true);
+            this.fireEvent(BI.ButtonGroup.EVENT_CHANGE, this.buttons[0].getValue(), this.buttons[0]);
+        } else if (this.getValue().length === 1 && BI.isEqual(this.getValue()[0], BICst.LIST_LABEL_TYPE.ALL)) {
+            this.buttons[0].setSelected(true);
+        }
+        else {
+            this.buttons[0].setSelected(false);
+        }
+    },
+
+    _checkBtnStyle: function () {
+        BI.each(this.buttons, function (idx, btn) {
+            if (btn.isSelected()) {
+                btn.doHighLight();
+            } else {
+                btn.unHighLight();
+            }
+        });
+    },
+
+    removeAllItems: function () {
+        var indexes = [];
+        for (var i = 1; i < this.buttons.length; i++) {
+            indexes.push(i);
+        }
+        this.removeItemAt(indexes);
+    },
+
+    setValue: function (v) {
+        var self = this;
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected && item.setSelected(true);
+            } else {
+                item.setSelected && item.setSelected(false);
+            }
+        });
+        var currentValues = this.getValue();
+        this.otherValues = [];
+        BI.each(v, function (idx, value) {
+            if (currentValues.indexOf(value) === -1) {
+                self.otherValues.push(value);
+            }
+        });
+        this._checkBtnState();
+        this._checkBtnStyle();
+
+    },
+
+    getValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.isSelected && item.isSelected()) {
+                v.push(item.getValue());
+            }
+        });
+        v = v.concat(this.otherValues || []);
+        return v;
+    }
+});
+
+$.shortcut('bi.list_label_item_group', BI.ListLabelItemGroup);
+/**
+ * 文本标签
+ *
+ * Created by fay on 2016/9/11.
+ */
+BI.ListLabel = BI.inherit(BI.Widget, {
+
+    _constant: {
+        MAX_COLUMN_SIZE: 40,
+        DEFAULT_LABEL_GAP: 15,
+        DEFAULT_RIGHT_GAP: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ListLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-list-label",
+            title: BI.i18nText("BI-List_Label_Con"),
+            showTitle: true,
+            items: [],
+            height: 40
+        })
+    },
+
+    _init: function () {
+        BI.ListLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.items = BI.clone(o.items);
+        this.items.unshift({
+            text: BI.i18nText("BI-Basic_Nolimited"),
+            value: BICst.LIST_LABEL_TYPE.ALL
+        });
+        this.title = BI.createWidget({
+            type: "bi.label",
+            text: o.title + BI.i18nText("BI-Basic_Colon"),
+            title: o.title,
+            height: o.height
+        });
+
+        this.container = BI.createWidget({
+            type: "bi.list_label_item_group",
+            items: BI.createItems(this.items.slice(0, this._constant.MAX_COLUMN_SIZE), {
+                type: "bi.text_button",
+                height: o.height,
+                rgap: this._constant.DEFAULT_RIGHT_GAP
+            }),
+            layouts: [{
+                type: "bi.inline_vertical_adapt",
+                rgap: this._constant.DEFAULT_LABEL_GAP,
+                height: o.height
+            }]
+        });
+        this.container.on(BI.ButtonGroup.EVENT_CHANGE, function (value) {
+            self.fireEvent(BI.ListLabel.EVENT_CHANGE, value);
+        });
+        this.minTip = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-No_Selected_Value"),
+            disabled: true,
+            height: o.height
+        });
+        this.maxTip = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-Max_Show_40_Labels"),
+            disabled: true,
+            height: o.height
+        });
+
+        this.checkTipsState(o.items);
+        this.right = BI.createWidget({
+            type: "bi.horizontal",
+            items: [this.container, this.minTip, this.maxTip],
+            height: o.height
+        });
+
+        o.showTitle ? BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.title,
+                left:0,
+                right:0,
+                top:0,
+                bottom:0,
+                width: 60
+            }, {
+                el: this.right,
+                left: 65,
+                right:0,
+                top:0,
+                bottom:0
+            }],
+            element: this
+        }) : BI.createWidget({
+            type: "bi.horizontal",
+            items: [this.right],
+            element: this
+        });
+    },
+
+    addItems: function (v) {
+        this.checkTipsState(v);
+        this.container.addItems(v.slice(0, this._constant.MAX_COLUMN_SIZE - 1));
+    },
+
+    checkTipsState: function (v) {
+        if (BI.isEmptyArray(v)) {
+            this.minTip.setVisible(true);
+            this.container.setVisible(false);
+        } else {
+            this.minTip.setVisible(false);
+            this.container.setVisible(true);
+        }
+        if (v.length >= this._constant.MAX_COLUMN_SIZE) {
+            this.maxTip.setVisible(true);
+        } else {
+            this.maxTip.setVisible(false);
+        }
+    },
+
+    removeAllItems: function () {
+        this.container.removeAllItems();
+    },
+
+    getSelectedButtons: function () {
+        return this.container.isVisible() ? this.container.getSelectedButtons() : [];
+    },
+
+    getAllButtons: function () {
+        return this.container.getAllButtons();
+    },
+
+    setTitle: function (title) {
+        this.title.setText(title + BI.i18nText("BI-Basic_Colon"));
+        this.title.setTitle(title);
+    },
+
+    setItems: function (items) {
+        this.removeAllItems();
+        this.addItems(BI.createItems(items, {
+            type: "bi.text_button",
+            height: this.options.height,
+            rgap: this._constant.DEFAULT_RIGHT_GAP
+        }));
+    },
+
+    populate: function (v) {
+        this.setTitle(v.title || BI.i18nText("BI-List_Label_Con"));
+        this.setItems(v.items || []);
+    },
+
+    setValue: function (v) {
+        this.container.setValue(v);
+    },
+
+    getValue: function () {
+        return this.container.getValue();
+    }
+});
+
+BI.ListLabel.EVENT_CHANGE = 'BI.ListLabel.EVENT_CHANGE';
+$.shortcut('bi.list_label', BI.ListLabel);/**
+ * 月份下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.MonthCombo
+ * @extends BI.Trigger
+ */
+BI.MonthCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.MonthCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.month_trigger"
+        });
+
+        this.trigger.on(BI.MonthTrigger.EVENT_CONFIRM, function (v) {
+            if(this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getValue());
+            }else if(!this.getKey()){
+                self.setValue();
+            }
+            self.fireEvent(BI.MonthCombo.EVENT_CONFIRM);
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_START, function () {
+            self.combo.hideView();
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_STOP, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_CHANGE, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.month_popup"
+        });
+        this.popup.on(BI.MonthPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MonthCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                el: this.popup
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+
+BI.MonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.month_combo', BI.MonthCombo);/**
+ * 月份展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.MonthPopup
+ * @extends BI.Trigger
+ */
+BI.MonthPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-popup"
+        });
+    },
+
+    _init: function () {
+        BI.MonthPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        //纵向排列月
+        var month = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11];
+        var items = [];
+        items.push(month.slice(0, 2));
+        items.push(month.slice(2, 4));
+        items.push(month.slice(4, 6));
+        items.push(month.slice(6, 8));
+        items.push(month.slice(8, 10));
+        items.push(month.slice(10, 12));
+        items = BI.map(items, function (i, item) {
+            return BI.map(item, function (j, td) {
+                return {
+                    type: "bi.text_item",
+                    cls: "bi-list-item-active",
+                    textAlign: "center",
+                    whiteSpace: "nowrap",
+                    once: false,
+                    forceSelected: true,
+                    height: 23,
+                    width: 38,
+                    value: td,
+                    text: td + 1
+                };
+            });
+        });
+
+        this.month = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(items, {}),
+            layouts: [BI.LogicFactory.createLogic("table", BI.extend({
+                dynamic: true
+            }, {
+                columns: 2,
+                rows: 6,
+                columnSize: [1 / 2, 1 / 2],
+                rowSize: 25
+            })), {
+                type: "bi.center_adapt",
+                vgap: 1,
+                hgap: 2
+            }]
+        });
+
+        this.month.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MonthPopup.EVENT_CHANGE);
+            }
+        })
+    },
+
+    getValue: function () {
+        return this.month.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.month.setValue([v]);
+    }
+});
+BI.MonthPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.month_popup", BI.MonthPopup);/**
+ * 月份trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.MonthTrigger
+ * @extends BI.Trigger
+ */
+BI.MonthTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 25,
+        errorText: BI.i18nText("BI-Month_Trigger_Error_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-month-trigger",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.MonthTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 12);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.MonthTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_STOP);
+        });
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        text: BI.i18nText("BI-Multi_Date_Month"),
+                        baseCls: "bi-trigger-month-text",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+    setValue: function (v) {
+        if(BI.isNotNull(v)){
+            this.editor.setState(v + 1);
+            this.editor.setValue(v + 1);
+            this.editor.setTitle(v + 1);
+            return;
+        }
+        this.editor.setState();
+        this.editor.setValue();
+        this.editor.setTitle();
+    },
+    getKey: function () {
+        return this.editor.getValue() | 0;
+    },
+    getValue: function () {
+        return this.editor.getValue() - 1;
+    }
+});
+BI.MonthTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.MonthTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.MonthTrigger.EVENT_START = "EVENT_START";
+BI.MonthTrigger.EVENT_STOP = "EVENT_STOP";
+BI.MonthTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.month_trigger", BI.MonthTrigger);/**
+ * 新建并选中某个分组按钮
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupAddButton
+ * @extends BI.BasicButton
+ */
+BI.Move2GroupAddButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.Move2GroupAddButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + ' bi-move2group-add-button',
+            shadow: true,
+            isShadowShowingOnSelected: true,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.Move2GroupAddButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            text: BI.i18nText("BI-Create_And_Move_To") + "\"江苏\"",
+            height: o.height
+        })
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "move2group-add-font"
+                },
+                width: 30
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    setValue: function (v) {
+        this.text.setValue(BI.i18nText("BI-Create_And_Move_To") + "\"" + v + "\"");
+        this.setTitle(BI.i18nText("BI-Create_And_Move_To") + "\"" + v + "\"", {
+            container: "body"
+        });
+    },
+
+    doClick: function () {
+        BI.Move2GroupAddButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.Move2GroupAddButton.EVENT_CHANGE);
+        }
+    }
+});
+BI.Move2GroupAddButton.EVENT_CHANGE = "Move2GroupAddButton.EVENT_CHANGE";
+$.shortcut('bi.move2group_add_button', BI.Move2GroupAddButton);/**
+ * 移动到分组下拉框
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupCombo
+ * @extends BI.Widget
+ */
+BI.Move2GroupCombo = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Move2GroupCombo.superclass._defaultConfig.apply(this, arguments)
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-move2group-combo",
+            height: 30,
+            tipType: "warning",
+            items: []
+        });
+    },
+    _init: function () {
+        BI.Move2GroupCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.button",
+            text: BI.i18nText("BI-Move_To_Group"),
+            title: o.title,
+            height: o.height
+        });
+
+        this.tools = BI.createWidget({
+            type: "bi.move2group_bar"
+        });
+
+        this.tools.on(BI.Move2GroupBar.EVENT_START, function () {
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_EMPTY, function () {
+            self.combo.adjustHeight();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_CLICK_BUTTON, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CLICK_NEW_BUTTON);
+            self.searcher.stopSearch();
+            self.combo.hideView();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_CHANGE, function () {
+            this.setButtonVisible(!self.searcher.hasMatched());
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+
+        this.popup = this._createPopup(this.options.items);
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: this.tools,
+            adapter: this.popup
+        });
+
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CONFIRM);
+            self.combo.hideView();
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            el: this.trigger,
+            isNeedAdjustWidth: false,
+            popup: {
+                width: 200,
+                stopPropagation: false,
+                el: this.popup,
+                tool: this.searcher
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_CHANGE, function () {
+            self.combo.hideView();
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CONFIRM);
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.searcher.stopSearch();
+        })
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.single_select_item",
+            height: 25,
+            handler: function (v) {
+
+            }
+        })
+    },
+
+    _createPopup: function (items, opt) {
+        return BI.createWidget(BI.extend({
+            type: "bi.button_group",
+            items: this._createItems(items),
+            chooseType: 0,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        }, opt));
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.combo.populate(this._createItems(items));
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+    setEnable: function (enable) {
+        this.combo.setEnable.apply(this.combo, arguments);
+    },
+
+    getTargetValue: function () {
+        return this.tools.getValue();
+    },
+
+    getValue: function () {
+        var value = this.searcher.getValue();
+        return value[0];
+
+    }
+});
+BI.Move2GroupCombo.EVENT_BEFORE_POPUPVIEW = "Move2GroupCombo.EVENT_BEFORE_POPUPVIEW";
+BI.Move2GroupCombo.EVENT_CHANGE = "Move2GroupCombo.EVENT_CHANGE";
+BI.Move2GroupCombo.EVENT_CONFIRM = "Move2GroupCombo.EVENT_CONFIRM";
+BI.Move2GroupCombo.EVENT_CLICK_NEW_BUTTON = "Move2GroupCombo.EVENT_CLICK_NEW_BUTTON";
+$.shortcut('bi.move2group_combo', BI.Move2GroupCombo);/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupBar
+ * @extends BI.Widget
+ */
+BI.Move2GroupBar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Move2GroupBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-move2group-bar"
+        })
+    },
+    _init: function () {
+        BI.Move2GroupBar.superclass._init.apply(this, arguments);
+        var self = this;
+        this.search = BI.createWidget({
+            type: "bi.text_editor",
+            watermark: BI.i18nText("BI-Search_And_Create_Group"),
+            allowBlank: true
+        });
+
+        this.search.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+
+        this.search.on(BI.TextEditor.EVENT_CHANGE, function () {
+            self.button.setValue(this.getValue());
+            if (this.getValue() !== "") {
+                self.fireEvent(BI.Move2GroupBar.EVENT_CHANGE);
+            }
+        });
+
+        this.search.on(BI.TextEditor.EVENT_EMPTY, function () {
+            self.button.invisible();
+            self.fireEvent(BI.Move2GroupBar.EVENT_EMPTY);
+        });
+
+        this.search.on(BI.TextEditor.EVENT_START, function () {
+            self.button.visible();
+            self.fireEvent(BI.Move2GroupBar.EVENT_START);
+        });
+
+        this.button = BI.createWidget({
+            type: "bi.move2group_add_button"
+        });
+
+        this.button.on(BI.Move2GroupAddButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Move2GroupBar.EVENT_CLICK_BUTTON);
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            vgap: 5,
+            hgap: 5,
+            items: [this.search, this.button]
+        });
+
+        this.button.invisible();
+    },
+
+    blur: function(){
+        this.search.blur();
+    },
+
+    setButtonVisible: function (b) {
+        this.button.setVisible(b);
+    },
+
+    getValue: function () {
+        return this.search.getValue();
+    },
+
+    setValue: function (v) {
+        this.search.setValue(v);
+        this.button.setValue(v);
+    }
+});
+BI.Move2GroupBar.EVENT_START = "Move2GroupBar.EVENT_START";
+BI.Move2GroupBar.EVENT_EMPTY = "Move2GroupBar.EVENT_EMPTY";
+BI.Move2GroupBar.EVENT_CHANGE = "Move2GroupBar.EVENT_CHANGE";
+BI.Move2GroupBar.EVENT_CLICK_BUTTON = "Move2GroupBar.EVENT_CLICK_BUTTON";
+$.shortcut("bi.move2group_bar", BI.Move2GroupBar);/**
+ * Created by fay on 2016/9/14.
+ */
+BI.TextLabelItemGroup = BI.inherit(BI.ButtonGroup, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextLabelItemGroup.superclass._defaultConfig.apply(this, arguments), {
+            chooseType: BI.Selection.Multi
+        });
+    },
+
+    _init: function () {
+        BI.TextLabelItemGroup.superclass._init.apply(this, arguments);
+        this._checkBtnStyle();
+    },
+
+    _btnsCreator: function (items) {
+        var self = this, args = Array.prototype.slice.call(arguments), o = this.options;
+        var buttons = this._createBtns(items);
+        args[0] = buttons;
+
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    switch (o.chooseType) {
+                        case BI.ButtonGroup.CHOOSE_TYPE_MULTI:
+                            if (BI.isEmptyString(btn.getValue())) {
+                                self.setValue([]);
+                            } else {
+                                self._checkBtnStyle();
+                            }
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                            self.setValue(btn.getValue());
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_NONE:
+                            self.setValue([]);
+                            break;
+                    }
+                    self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            btn.on(BI.Events.DESTROY, function () {
+                BI.remove(self.buttons, btn);
+            })
+        });
+
+        return buttons;
+    },
+
+    _checkBtnStyle: function () {
+        var self = this;
+        var flag = BI.isEmptyArray(this.getValue());
+        BI.each(this.buttons, function (idx, btn) {
+            if (flag && BI.isEmptyString(btn.getValue())) {
+                btn.setSelected(true);
+                btn.doHighLight();
+            }
+            if (!flag && BI.isEmptyString(btn.getValue())) {
+                btn.setSelected(false);
+                btn.unHighLight();
+            }
+            if (btn.isSelected()) {
+                btn.doHighLight();
+            } else {
+                btn.unHighLight();
+            }
+        });
+    },
+
+    setValue: function (v) {
+        BI.TextLabelItemGroup.superclass.setValue.apply(this, arguments);
+        this._checkBtnStyle();
+    }
+});
+
+$.shortcut('bi.text_label_item_group', BI.TextLabelItemGroup);
+/**
+ * 文本标签
+ *
+ * Created by fay on 2016/9/11.
+ */
+BI.TextLabel = BI.inherit(BI.Widget, {
+
+    _constant: {
+        MAX_COLUMN_SIZE: 40
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.TextLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-label",
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var title = BI.createWidget({
+            type: "bi.label",
+            text: o.title + ":"
+        });
+        this.container = BI.createWidget({
+            type: "bi.text_label_item_group",
+            items: BI.createItems(o.items.slice(0, this._constant.MAX_COLUMN_SIZE), {
+                type: "bi.text_button"
+            }),
+            layouts: [{
+                type: "bi.horizontal",
+
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.horizontal",
+            items: [title, this.container],
+            element: this
+        })
+    },
+    
+    setValue: function (v) {
+        this.container.setValue(v);
+    },
+    
+    getValue: function () {
+        return this.container.getValue();
+    }
+});
+
+$.shortcut('bi.text_label', BI.TextLabel);(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.MultiDateCard
+     * @extends BI.Widget
+     * @abstract
+     */
+    BI.MultiDateCard = BI.inherit(BI.Widget, {
+
+        constants: {
+            lgap: 80,
+            itemHeight: 35,
+            defaultEditorValue: "1"
+        },
+
+        _defaultConfig: function () {
+            return $.extend(BI.MultiDateCard.superclass._defaultConfig.apply(this, arguments), {});
+        },
+
+        dateConfig: function () {
+
+        },
+
+        defaultSelectedItem: function () {
+
+        },
+
+        _init: function () {
+            BI.MultiDateCard.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+
+            this.label = BI.createWidget({
+                type: 'bi.label',
+                height: this.constants.itemHeight,
+                textAlign: "left",
+                text: BI.i18nText("BI-Multi_Date_Relative_Current_Time"),
+                cls: 'bi-multidate-inner-label'
+            });
+            this.radioGroup = BI.createWidget({
+                type: "bi.button_group",
+                chooseType: 0,
+                items: BI.createItems(this.dateConfig(), {
+                    type: 'bi.multidate_segment',
+                    height: this.constants.itemHeight
+                }),
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            });
+
+            this.radioGroup.on(BI.Controller.EVENT_CHANGE, function (type) {
+                if (type === BI.Events.CONFIRM) {
+                    self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+                }
+            });
+            this.radioGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+                self.setValue(self.getValue());
+                self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+            });
+            BI.createWidget({
+                element: this,
+                type: 'bi.center_adapt',
+                lgap: this.constants.lgap,
+                items: [{
+                    type: 'bi.vertical',
+                    items: [this.label, this.radioGroup]
+                }]
+            });
+        },
+
+        getValue: function () {
+            var button = this.radioGroup.getSelectedButtons()[0];
+            var type = button.getValue(), value = button.getInputValue();
+            return {
+                type: type,
+                value: value
+            }
+        },
+
+        _isTypeAvaliable: function (type) {
+            var res = false;
+            BI.find(this.dateConfig(), function (i, item) {
+                if (item.value === type) {
+                    res = true;
+                    return true;
+                }
+            });
+            return res;
+        },
+
+        setValue: function (v) {
+            var self = this;
+            if (BI.isNotNull(v) && this._isTypeAvaliable(v.type)) {
+                this.radioGroup.setValue(v.type);
+                BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+                    if (button.isEditorExist() === true && button.isSelected()) {
+                        button.setInputValue(v.value);
+                        button.setEnable(true);
+                    } else {
+                        button.setInputValue(self.constants.defaultEditorValue);
+                        button.setEnable(false);
+                    }
+                });
+            } else {
+                this.radioGroup.setValue(this.defaultSelectedItem());
+                BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+                    button.setInputValue(self.constants.defaultEditorValue);
+                    if (button.isEditorExist() === true && button.isSelected()) {
+                        button.setEnable(true);
+                    } else {
+                        button.setEnable(false);
+                    }
+                });
+            }
+        },
+
+        getCalculationValue: function () {
+            var valueObject = this.getValue();
+            var type = valueObject.type, value = valueObject.value;
+            switch (type) {
+                case BICst.MULTI_DATE_DAY_PREV:
+                    return new Date().getOffsetDate(-1 * value);
+                case BICst.MULTI_DATE_DAY_AFTER:
+                    return new Date().getOffsetDate(value);
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    return new Date();
+                case BICst.MULTI_DATE_MONTH_PREV:
+                    return new Date().getBeforeMultiMonth(value);
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                    return new Date().getAfterMultiMonth(value);
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                    return new Date(new Date().getFullYear(), new Date().getMonth(), 1);
+                case BICst.MULTI_DATE_MONTH_END:
+                    return new Date(new Date().getFullYear(), new Date().getMonth(), (new Date().getLastDateOfMonth()).getDate());
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                    return new Date().getBeforeMulQuarter(value);
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                    return new Date().getAfterMulQuarter(value);
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                    return new Date().getQuarterStartDate();
+                case BICst.MULTI_DATE_QUARTER_END:
+                    return new Date().getQuarterEndDate();
+                case BICst.MULTI_DATE_WEEK_PREV:
+                    return new Date().getOffsetDate(-7 * value);
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                    return new Date().getOffsetDate(7 * value);
+                case BICst.MULTI_DATE_YEAR_PREV:
+                    return new Date((new Date().getFullYear() - 1 * value), new Date().getMonth(), new Date().getDate());
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                    return new Date((new Date().getFullYear() + 1 * value), new Date().getMonth(), new Date().getDate());
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                    return new Date(new Date().getFullYear(), 0, 1);
+                case BICst.MULTI_DATE_YEAR_END:
+                    return new Date(new Date().getFullYear(), 11, 31);
+            }
+        }
+    });
+    BI.MultiDateCard.EVENT_CHANGE = "EVENT_CHANGE";
+})(jQuery);BICst.MULTI_DATE_YMD_CARD = 1;
+BICst.MULTI_DATE_YEAR_CARD = 2;
+BICst.MULTI_DATE_QUARTER_CARD = 3;
+BICst.MULTI_DATE_MONTH_CARD = 4;
+BICst.MULTI_DATE_WEEK_CARD = 5;
+BICst.MULTI_DATE_DAY_CARD = 6;
+BICst.MULTI_DATE_SEGMENT_NUM = {};
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV] = BI.i18nText("BI-Multi_Date_Year_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER] = BI.i18nText("BI-Multi_Date_Year_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN] = BI.i18nText("BI-Multi_Date_Year_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END] = BI.i18nText("BI-Multi_Date_Year_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV] = BI.i18nText("BI-Multi_Date_Quarter_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER] = BI.i18nText("BI-Multi_Date_Quarter_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN] = BI.i18nText("BI-Multi_Date_Quarter_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END] = BI.i18nText("BI-Multi_Date_Quarter_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV] = BI.i18nText("BI-Multi_Date_Month_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER] = BI.i18nText("BI-Multi_Date_Month_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN] = BI.i18nText("BI-Multi_Date_Month_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END] = BI.i18nText("BI-Multi_Date_Month_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV] = BI.i18nText("BI-Multi_Date_Week_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER] = BI.i18nText("BI-Multi_Date_Week_Next");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV] = BI.i18nText("BI-Multi_Date_Day_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER] = BI.i18nText("BI-Multi_Date_Day_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY] = BI.i18nText("BI-Multi_Date_Today");
+
+(function ($) {
+    /**
+     * 日期控件
+     * @class BI.MultiDateCombo
+     * @extends BI.Widget
+     */
+    BI.MultiDateCombo = BI.inherit(BI.Single, {
+        constants: {
+            popupHeight: 259,
+            popupWidth: 270,
+            comboAdjustHeight: 1,
+            border: 1,
+            DATE_MIN_VALUE: "1900-01-01",
+            DATE_MAX_VALUE: "2099-12-31"
+        },
+        _defaultConfig: function () {
+            return BI.extend(BI.MultiDateCombo.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-combo',
+                height: 24
+            });
+        },
+        _init: function () {
+            BI.MultiDateCombo.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.storeTriggerValue = "";
+            var date = new Date();
+            this.storeValue = null;
+            this.trigger = BI.createWidget({
+                type: 'bi.date_trigger',
+                min: this.constants.DATE_MIN_VALUE,
+                max: this.constants.DATE_MAX_VALUE
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_KEY_DOWN, function(){
+                if(self.combo.isViewVisible()){
+                    self.combo.hideView();
+                }
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_STOP, function(){
+                if(!self.combo.isViewVisible()){
+                    self.combo.showView();
+                }
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function(){
+                self.combo.toggle();
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_FOCUS, function () {
+                self.storeTriggerValue = self.trigger.getKey();
+                if(!self.combo.isViewVisible()){
+                    self.combo.showView();
+                }
+                self.fireEvent(BI.MultiDateCombo.EVENT_FOCUS);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_ERROR, function () {
+                self.storeValue = {
+                    year: date.getFullYear(),
+                    month: date.getMonth()
+                };
+                self.popup.setValue();
+                self.fireEvent(BI.MultiDateCombo.EVENT_ERROR);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_VALID, function () {
+                self.fireEvent(BI.MultiDateCombo.EVENT_VALID);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_CONFIRM, function () {
+                if(self.combo.isViewVisible()) {
+                    return;
+                }
+                var dateStore = self.storeTriggerValue;
+                var dateObj = self.trigger.getKey();
+                if (BI.isNotEmptyString(dateObj) && !BI.isEqual(dateObj, dateStore)) {
+                    self.storeValue = self.trigger.getValue();
+                    self.setValue(self.trigger.getValue());
+                } else if (BI.isEmptyString(dateObj)) {
+                    self.storeValue = null;
+                    self.trigger.setValue();
+                }
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup = BI.createWidget({
+                type: "bi.multidate_popup",
+                min: this.constants.DATE_MIN_VALUE,
+                max: this.constants.DATE_MAX_VALUE
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE, function () {
+                self.setValue();
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE, function () {
+                var date = new Date();
+                self.setValue({
+                    year: date.getFullYear(),
+                    month: date.getMonth(),
+                    day: date.getDate()
+                });
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE, function () {
+                self.setValue(self.popup.getValue());
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE, function () {
+                self.setValue(self.popup.getValue());
+                self.combo.hideView();
+                //self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.combo = BI.createWidget({
+                type: 'bi.combo',
+                toggle: false,
+                isNeedAdjustHeight: false,
+                isNeedAdjustWidth: false,
+                el: this.trigger,
+                adjustLength: this.constants.comboAdjustHeight,
+                popup: {
+                    el: this.popup,
+                    maxHeight: this.constants.popupHeight,
+                    width: this.constants.popupWidth,
+                    stopPropagation: false
+                }
+            });
+            this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+                self.popup.setValue(self.storeValue);
+                self.fireEvent(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW);
+            });
+
+            var triggerBtn = BI.createWidget({
+                type: "bi.trigger_icon_button",
+                cls: "bi-trigger-date-button chart-date-normal-font",
+                width: 30,
+                height: 23
+            });
+            triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+                if (self.combo.isViewVisible()) {
+                    self.combo.hideView();
+                } else {
+                    self.combo.showView();
+                }
+            });
+            this.changeIcon = BI.createWidget({
+                type: "bi.icon_button",
+                cls: "bi-trigger-date-change widget-date-h-change-font",
+                width: 30,
+                height: 23,
+                invisible: true
+            });
+
+
+            BI.createWidget({
+                type: "bi.absolute",
+                element: this,
+                items: [{
+                    el: this.combo,
+                    top: 0,
+                    left: 0,
+                    right: 0,
+                    bottom: 0
+                }, {
+                    el: triggerBtn,
+                    top: 0,
+                    left: 0
+                }, {
+                    el: this.changeIcon,
+                    top: 0,
+                    right: 0
+                }]
+            })
+        },
+
+        _checkDynamicValue: function(v){
+            var type = null;
+            if (BI.isNotNull(v)) {
+                type = v.type
+            }
+            switch (type){
+                case BICst.MULTI_DATE_YEAR_PREV:
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                case BICst.MULTI_DATE_YEAR_END:
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                case BICst.MULTI_DATE_QUARTER_END:
+                case BICst.MULTI_DATE_MONTH_PREV:
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                case BICst.MULTI_DATE_MONTH_END:
+                case BICst.MULTI_DATE_WEEK_PREV:
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                case BICst.MULTI_DATE_DAY_PREV:
+                case BICst.MULTI_DATE_DAY_AFTER:
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    this.changeIcon.setVisible(true);
+                    break;
+                default:
+                    this.changeIcon.setVisible(false);
+                    break;
+            }
+        },
+
+        setValue: function (v) {
+            this.storeValue = v;
+            this.popup.setValue(v);
+            this.trigger.setValue(v);
+            this._checkDynamicValue(v)
+        },
+        getValue: function () {
+            return this.storeValue;
+        },
+        getKey: function(){
+            return this.trigger.getKey();
+        },
+        hidePopupView: function () {
+            this.combo.hideView();
+        }
+    });
+    $.shortcut('bi.multidate_combo', BI.MultiDateCombo);
+
+    BI.MultiDateCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+    BI.MultiDateCombo.EVENT_FOCUS = "EVENT_FOCUS";
+    BI.MultiDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+    BI.MultiDateCombo.EVENT_VALID = "EVENT_VALID";
+    BI.MultiDateCombo.EVENT_ERROR = "EVENT_ERROR";
+    BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW = "BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW";
+})(jQuery);(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.DayCard
+     * @extends BI.MultiDateCard
+     */
+    BI.DayCard = BI.inherit(BI.MultiDateCard, {
+
+        _defaultConfig: function () {
+            return $.extend(BI.DayCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-daycard'
+            });
+        },
+
+        _init: function () {
+            BI.DayCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                isEditorExist: true,
+                selected: true,
+                text: BI.i18nText("BI-Multi_Date_Day_Prev"),
+                value: BICst.MULTI_DATE_DAY_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Day_Next"),
+                    value: BICst.MULTI_DATE_DAY_AFTER
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_DAY_TODAY,
+                    text: BI.i18nText("BI-Multi_Date_Today")
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_DAY_PREV
+        }
+    });
+    BI.DayCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.daycard', BI.DayCard);
+})(jQuery);;
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.MonthCard
+     * @extends BI.MultiDateCard
+     */
+    BI.MonthCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.MonthCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-monthcard'
+            });
+        },
+
+        _init: function () {
+            BI.MonthCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                value: BICst.MULTI_DATE_MONTH_PREV,
+                text: BI.i18nText("BI-Multi_Date_Month_Prev")
+            },
+                {
+                    isEditorExist: true,
+                    value: BICst.MULTI_DATE_MONTH_AFTER,
+                    text: BI.i18nText("BI-Multi_Date_Month_Next")
+                },
+                {
+                    value: BICst.MULTI_DATE_MONTH_BEGIN,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Month_Begin")
+                },
+                {
+                    value: BICst.MULTI_DATE_MONTH_END,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Month_End")
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_MONTH_PREV;
+        }
+    });
+    BI.MonthCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.monthcard', BI.MonthCard);
+})(jQuery);(function ($) {
+    /**
+     * 日期控件
+     * @class BI.MultiDatePopup
+     * @extends BI.Widget
+     */
+    BI.MultiDatePopup = BI.inherit(BI.Widget, {
+        constants: {
+            tabHeight: 30,
+            tabWidth: 42,
+            titleHeight: 27,
+            itemHeight: 30,
+            triggerHeight: 24,
+            buttonWidth: 90,
+            buttonHeight: 25,
+            cardHeight: 229,
+            cardWidth: 270,
+            popupHeight: 259,
+            popupWidth: 270,
+            comboAdjustHeight: 1,
+            ymdWidth: 58,
+            lgap: 2,
+            border: 1
+        },
+        _defaultConfig: function () {
+            return BI.extend(BI.MultiDatePopup.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-popup',
+                width: 268,
+                height: 260
+            });
+        },
+        _init: function () {
+            BI.MultiDatePopup.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.storeValue = "";
+            this.textButton = BI.createWidget({
+                type: 'bi.text_button',
+                forceCenter: true,
+                cls: 'bi-multidate-popup-label',
+                shadow: true,
+                text: BI.i18nText("BI-Multi_Date_Today")
+            });
+            this.textButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE);
+            });
+            this.clearButton = BI.createWidget({
+                type: "bi.text_button",
+                forceCenter: true,
+                cls: 'bi-multidate-popup-button',
+                shadow: true,
+                text: BI.i18nText("BI-Basic_Clear")
+            });
+            this.clearButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE);
+            });
+            this.okButton = BI.createWidget({
+                type: "bi.text_button",
+                forceCenter: true,
+                cls: 'bi-multidate-popup-button',
+                shadow: true,
+                text: BI.i18nText("BI-Basic_OK")
+            });
+            this.okButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE);
+            });
+            this.dateTab = BI.createWidget({
+                type: 'bi.tab',
+                tab: {
+                    cls: "bi-multidate-popup-tab",
+                    height: this.constants.tabHeight,
+                    items: BI.createItems([{
+                        text: BI.i18nText("BI-Multi_Date_YMD"),
+                        value: BICst.MULTI_DATE_YMD_CARD,
+                        width: this.constants.ymdWidth
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Year"),
+                        value: BICst.MULTI_DATE_YEAR_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Quarter"),
+                        value: BICst.MULTI_DATE_QUARTER_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Month"),
+                        value: BICst.MULTI_DATE_MONTH_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Week"),
+                        value: BICst.MULTI_DATE_WEEK_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Day"),
+                        value: BICst.MULTI_DATE_DAY_CARD
+                    }], {
+                        width: this.constants.tabWidth,
+                        textAlign: "center",
+                        height: this.constants.itemHeight,
+                        cls: 'bi-multidate-popup-item'
+                    }),
+                    layouts: [{
+                        type: 'bi.left'
+                    }]
+                },
+                cardCreator: function (v) {
+                    switch (v) {
+                        case BICst.MULTI_DATE_YMD_CARD:
+                            self.ymd = BI.createWidget({
+                                type: "bi.date_calendar_popup",
+                                min: self.options.min,
+                                max: self.options.max
+                            });
+                            self.ymd.on(BI.DateCalendarPopup.EVENT_CHANGE, function () {
+                                self.fireEvent(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE);
+                            });
+                            return self.ymd;
+                        case BICst.MULTI_DATE_YEAR_CARD:
+                            self.year = BI.createWidget({
+                                type: "bi.yearcard"
+                            });
+                            self.year.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.year, v);
+                            });
+                            return self.year;
+                        case BICst.MULTI_DATE_QUARTER_CARD:
+                            self.quarter = BI.createWidget({
+                                type: 'bi.quartercard'
+                            });
+                            self.quarter.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.quarter, v);
+                            });
+                            return self.quarter;
+                        case BICst.MULTI_DATE_MONTH_CARD:
+                            self.month = BI.createWidget({
+                                type: 'bi.monthcard'
+                            });
+                            self.month.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.month, v);
+                            });
+                            return self.month;
+                        case BICst.MULTI_DATE_WEEK_CARD:
+                            self.week = BI.createWidget({
+                                type: 'bi.weekcard'
+                            });
+                            self.week.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.week, v);
+                            });
+                            return self.week;
+                        case BICst.MULTI_DATE_DAY_CARD:
+                            self.day = BI.createWidget({
+                                type: 'bi.daycard'
+                            });
+                            self.day.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.day, v);
+                            });
+                            return self.day;
+                    }
+                }
+            });
+            this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+            this.cur = BICst.MULTI_DATE_YMD_CARD;
+            this.dateTab.on(BI.Tab.EVENT_CHANGE, function () {
+                var v = self.dateTab.getSelect();
+                switch (v) {
+                    case BICst.MULTI_DATE_YMD_CARD:
+                        var date = this.getTab(self.cur).getCalculationValue();
+                        self.ymd.setValue({
+                            year: date.getFullYear(),
+                            month: date.getMonth(),
+                            day: date.getDate()
+                        });
+                        self._setInnerValue(self.ymd);
+                        break;
+                    case BICst.MULTI_DATE_YEAR_CARD:
+                        self.year.setValue(self.storeValue);
+                        self._setInnerValue(self.year);
+                        break;
+                    case BICst.MULTI_DATE_QUARTER_CARD:
+                        self.quarter.setValue(self.storeValue);
+                        self._setInnerValue(self.quarter);
+                        break;
+                    case BICst.MULTI_DATE_MONTH_CARD:
+                        self.month.setValue(self.storeValue);
+                        self._setInnerValue(self.month);
+                        break;
+                    case BICst.MULTI_DATE_WEEK_CARD:
+                        self.week.setValue(self.storeValue);
+                        self._setInnerValue(self.week);
+                        break;
+                    case BICst.MULTI_DATE_DAY_CARD:
+                        self.day.setValue(self.storeValue);
+                        self._setInnerValue(self.day);
+                        break;
+                }
+                self.cur = v;
+            });
+            this.dateButton = BI.createWidget({
+                type: "bi.grid",
+                items: [[this.clearButton, this.textButton, this.okButton]]
+            });
+            BI.createWidget({
+                element: this,
+                type: "bi.vtape",
+                items: [{
+                    el: this.dateTab
+                }, {
+                    el: this.dateButton,
+                    height: 30
+                }]
+            });
+        },
+        _setInnerValue: function (obj) {
+            if (this.dateTab.getSelect() === BICst.MULTI_DATE_YMD_CARD) {
+                this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                this.textButton.setEnable(true);
+            } else {
+                var date = obj.getCalculationValue();
+                date = date.print("%Y-%x-%e");
+                this.textButton.setValue(date);
+                this.textButton.setEnable(false);
+            }
+        },
+        setValue: function (v) {
+            this.storeValue = v;
+            var self = this, date;
+            var type, value;
+            if (BI.isNotNull(v)) {
+                type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value;
+                if(BI.isNull(value)){
+                    value = v;
+                }
+            }
+            switch (type) {
+                case BICst.MULTI_DATE_YEAR_PREV:
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                case BICst.MULTI_DATE_YEAR_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_YEAR_CARD);
+                    this.year.setValue({type: type, value: value});
+                    this.cur = BICst.MULTI_DATE_YEAR_CARD;
+                    self._setInnerValue(this.year);
+                    break;
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                case BICst.MULTI_DATE_QUARTER_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_QUARTER_CARD);
+                    this.cur = BICst.MULTI_DATE_QUARTER_CARD;
+                    this.quarter.setValue({type: type, value: value});
+                    self._setInnerValue(this.quarter);
+                    break;
+                case BICst.MULTI_DATE_MONTH_PREV:
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                case BICst.MULTI_DATE_MONTH_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_MONTH_CARD);
+                    this.cur = BICst.MULTI_DATE_MONTH_CARD;
+                    this.month.setValue({type: type, value: value});
+                    self._setInnerValue(this.month);
+                    break;
+                case BICst.MULTI_DATE_WEEK_PREV:
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_WEEK_CARD);
+                    this.cur = BICst.MULTI_DATE_WEEK_CARD;
+                    this.week.setValue({type: type, value: value});
+                    self._setInnerValue(this.week);
+                    break;
+                case BICst.MULTI_DATE_DAY_PREV:
+                case BICst.MULTI_DATE_DAY_AFTER:
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_DAY_CARD);
+                    this.cur = BICst.MULTI_DATE_DAY_CARD;
+                    this.day.setValue({type: type, value: value});
+                    self._setInnerValue(this.day);
+                    break;
+                default:
+                    if (BI.isNull(value) || BI.isEmptyObject(value)) {
+                        var date = new Date();
+                        this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+                        this.ymd.setValue({
+                            year: date.getFullYear(),
+                            month: date.getMonth(),
+                            day: date.getDate()
+                        });
+                        this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                    } else {
+                        this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+                        this.ymd.setValue(value);
+                        this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                    }
+                    this.textButton.setEnable(true);
+                    break;
+            }
+        },
+        getValue: function () {
+            var tab = this.dateTab.getSelect();
+            switch (tab) {
+                case BICst.MULTI_DATE_YMD_CARD:
+                    return this.ymd.getValue();
+                case BICst.MULTI_DATE_YEAR_CARD:
+                    return this.year.getValue();
+                case BICst.MULTI_DATE_QUARTER_CARD:
+                    return this.quarter.getValue();
+                case BICst.MULTI_DATE_MONTH_CARD:
+                    return this.month.getValue();
+                case BICst.MULTI_DATE_WEEK_CARD:
+                    return this.week.getValue();
+                case BICst.MULTI_DATE_DAY_CARD:
+                    return this.day.getValue();
+            }
+        }
+    });
+    BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE";
+    BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE = "BUTTON_lABEL_EVENT_CHANGE";
+    BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE = "BUTTON_CLEAR_EVENT_CHANGE";
+    BI.MultiDatePopup.CALENDAR_EVENT_CHANGE = "CALENDAR_EVENT_CHANGE";
+    $.shortcut('bi.multidate_popup', BI.MultiDatePopup);
+})(jQuery);(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.QuarterCard
+     * @extends BI.MultiDateCard
+     */
+    BI.QuarterCard = BI.inherit(BI.MultiDateCard, {
+
+        _defaultConfig: function () {
+            return $.extend(BI.QuarterCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-quartercard'
+            });
+        },
+
+        _init: function () {
+            BI.QuarterCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                value: BICst.MULTI_DATE_QUARTER_PREV,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Quarter_Prev")
+            },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_AFTER,
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_Next")
+                },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_BEGIN,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_Begin")
+                },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_END,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_End")
+                }]
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_QUARTER_PREV;
+        }
+    });
+    BI.QuarterCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.quartercard', BI.QuarterCard);
+})(jQuery);(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.MultiDateSegment
+     * @extends BI.Single
+     */
+    BI.MultiDateSegment = BI.inherit(BI.Single, {
+        constants: {
+            itemHeight: 24,
+            maxGap: 15,
+            minGap: 10,
+            textWidth: 30,
+            defaultEditorValue: "1"
+        },
+
+        _defaultConfig: function () {
+            return $.extend(BI.MultiDateSegment.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-segment',
+                text: "",
+                width: 130,
+                height: 30,
+                isEditorExist: true,
+                selected: false,
+                defaultEditorValue: "1"
+            });
+        },
+
+        _init: function () {
+            BI.MultiDateSegment.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.radio = BI.createWidget({
+                type: "bi.radio",
+                selected: opts.selected
+            });
+            this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            this.textEditor = BI.createWidget({
+                type: 'bi.text_editor',
+                value: this.constants.defaultEditorValue,
+                title:this.constants.defaultEditorValue,
+                cls: 'bi-multidate-editor',
+                width: this.constants.textWidth,
+                height: this.constants.itemHeight
+            });
+            this.textEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            this.textEditor.on(BI.TextEditor.EVENT_CONFIRM, function () {
+                this.setTitle(this.getValue());
+            });
+            this.text = BI.createWidget({
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'bi-multidate-normal-label',
+                text: opts.text,
+                height: this.constants.itemHeight
+            });
+            this._createSegment();
+        },
+        _createSegment: function () {
+            if (this.options.isEditorExist === true) {
+                return BI.createWidget({
+                    element: this,
+                    type: 'bi.left',
+                    items: [{
+                        el: {
+                            type: "bi.center_adapt",
+                            items: [this.radio],
+                            height: this.constants.itemHeight
+                        },
+                        lgap: 0
+                    },
+                        {
+                            el: {
+                                type: "bi.center_adapt",
+                                items: [this.textEditor],
+                                widgetName: 'textEditor'
+                            },
+                            lgap: this.constants.maxGap
+                        },
+                        {
+                            el: this.text,
+                            lgap: this.constants.minGap
+                        }]
+                });
+            }
+            return BI.createWidget({
+                element: this,
+                type: 'bi.left',
+                items: [{
+                    el: {
+                        type: "bi.center_adapt",
+                        items: [this.radio],
+                        height: this.constants.itemHeight
+                    },
+                    lgap: 0
+                },
+                    {
+                        el: this.text,
+                        lgap: this.constants.maxGap
+                    }]
+            })
+        },
+        setSelected: function (v) {
+            if (BI.isNotNull(this.radio)) {
+                this.radio.setSelected(v);
+            }
+        },
+        isSelected: function () {
+            return this.radio.isSelected();
+        },
+        getValue: function () {
+            return this.options.value;
+        },
+        getInputValue: function () {
+            return this.textEditor.getValue() | 0;
+        },
+        setInputValue: function (v) {
+            this.textEditor.setValue(v);
+        },
+        isEditorExist: function () {
+            return this.options.isEditorExist;
+        },
+        setEnable: function (b) {
+            BI.Editor.superclass.setEnable.apply(this, arguments);
+            this.textEditor && this.textEditor.setEnable(b);
+        }
+    });
+    BI.MultiDateSegment.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.multidate_segment', BI.MultiDateSegment);
+})(jQuery);;
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.WeekCard
+     * @extends BI.MultiDateCard
+     */
+    BI.WeekCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.WeekCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-weekcard'
+            });
+        },
+
+        _init: function () {
+            BI.WeekCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Week_Prev"),
+                value: BICst.MULTI_DATE_WEEK_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Week_Next"),
+                    value: BICst.MULTI_DATE_WEEK_AFTER
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_WEEK_PREV;
+        }
+    });
+    BI.WeekCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.weekcard', BI.WeekCard);
+})(jQuery);(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.YearCard
+     * @extends BI.MultiDateCard
+     */
+    BI.YearCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.YearCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-yearcard'
+            });
+        },
+
+        _init: function () {
+            BI.YearCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Year_Prev"),
+                value: BICst.MULTI_DATE_YEAR_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Year_Next"),
+                    value: BICst.MULTI_DATE_YEAR_AFTER
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_YEAR_BEGIN,
+                    text: BI.i18nText("BI-Multi_Date_Year_Begin")
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_YEAR_END,
+                    text: BI.i18nText("BI-Multi_Date_Year_End")
+                }]
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_YEAR_PREV;
+        }
+    });
+    BI.YearCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.yearcard', BI.YearCard);
+})(jQuery);/**
+ * @class BI.MultiLayerSelectTreeCombo
+ * @extends BI.Widget
+ */
+BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer_select_tree-combo",
+            isDefaultInit: false,
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.multilayer_select_tree_popup",
+            isDefaultInit: o.isDefaultInit,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.MultiLayerSelectTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MultiLayerSelectTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+BI.MultiLayerSelectTreeCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_select_tree_combo", BI.MultiLayerSelectTreeCombo);/**
+ * guy
+ * 二级树
+ * @class BI.MultiLayerSelectLevelTree
+ * @extends BI.Select
+ */
+BI.MultiLayerSelectLevelTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectLevelTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-select-level-tree",
+            isDefaultInit: false,
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectLevelTree.superclass._init.apply(this, arguments);
+
+        this.initTree(this.options.items);
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {};
+            node.layer = layer;
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.multilayer_select_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.multilayer_select_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_select_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+
+                self._formatItems(node.children, layer + 1);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.multilayer_single_tree_last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _assertId: function (sNodes) {
+        BI.each(sNodes, function (i, node) {
+            node.id = node.id || BI.UUID();
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.empty();
+        this._assertId(nodes);
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: {
+                type: "bi.select_tree_expander",
+                isDefaultInit: o.isDefaultInit,
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            },
+
+            items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0),
+            itemsCreator: o.itemsCreator,
+
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.Single,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+
+    populate: function (nodes) {
+        this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0));
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    getAllLeaves: function () {
+        return this.tree.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree.getNodeByValue(id);
+    }
+});
+BI.MultiLayerSelectLevelTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multilayer_select_level_tree", BI.MultiLayerSelectLevelTree);/**
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSelectTreePopup
+ * @extends BI.Pane
+ */
+
+BI.MultiLayerSelectTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-select-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            isDefaultInit: false,
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.multilayer_select_level_tree',
+            isDefaultInit: o.isDefaultInit,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            scrollable: true,
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiLayerSelectTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.MultiLayerSelectTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.MultiLayerSelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_select_tree_popup", BI.MultiLayerSelectTreePopup);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-first-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_first_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_first_plus_group_node", BI.MultiLayerSelectTreeFirstPlusGroupNode);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-last-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_last_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_last_plus_group_node", BI.MultiLayerSelectTreeLastPlusGroupNode);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-mid-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_mid_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_mid_plus_group_node", BI.MultiLayerSelectTreeMidPlusGroupNode);/**
+ * 多层级下拉单选树
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSingleTreeCombo
+ * @extends BI.Widget
+ */
+BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-singletree-combo",
+            isDefaultInit: false,
+            height: 30,
+            text: "",
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.multilayer_single_tree_popup",
+            isDefaultInit: o.isDefaultInit,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.MultiLayerSingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MultiLayerSingleTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+
+BI.MultiLayerSingleTreeCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_single_tree_combo", BI.MultiLayerSingleTreeCombo);/**
+ * guy
+ * 二级树
+ * @class BI.MultiLayerSingleLevelTree
+ * @extends BI.Single
+ */
+BI.MultiLayerSingleLevelTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleLevelTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-single-level-tree",
+            isDefaultInit: false,
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleLevelTree.superclass._init.apply(this, arguments);
+
+        this.initTree(this.options.items);
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {};
+            node.layer = layer;
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.multilayer_single_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.multilayer_single_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+
+                self._formatItems(node.children, layer + 1);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.multilayer_single_tree_last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _assertId: function (sNodes) {
+        BI.each(sNodes, function (i, node) {
+            node.id = node.id || BI.UUID();
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.empty();
+        this._assertId(nodes);
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: {
+                isDefaultInit: o.isDefaultInit,
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            },
+
+            items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0),
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (items) {
+                    callback(BI.Tree.transformToTreeFormat(items), 0)
+                })
+            },
+
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.Single,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+
+    populate: function (nodes) {
+        this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0));
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    getAllLeaves: function () {
+        return this.tree.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree.getNodeByValue(id);
+    }
+});
+BI.MultiLayerSingleLevelTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multilayer_single_level_tree", BI.MultiLayerSingleLevelTree);
+/**
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSingleTreePopup
+ * @extends BI.Pane
+ */
+
+BI.MultiLayerSingleTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-singletree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            isDefaultInit: false,
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.multilayer_single_level_tree',
+            isDefaultInit: o.isDefaultInit,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            scrollable: true,
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiLayerSingleTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.MultiLayerSingleTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.MultiLayerSingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_single_tree_popup", BI.MultiLayerSingleTreePopup);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-first-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.first_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_first_plus_group_node", BI.MultiLayerSingleTreeFirstPlusGroupNode);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-last-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.last_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_last_plus_group_node", BI.MultiLayerSingleTreeLastPlusGroupNode);/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-mid-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.mid_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_mid_plus_group_node", BI.MultiLayerSingleTreeMidPlusGroupNode);/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeFirstTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeFirstTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-first-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.first_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_first_tree_leaf_item", BI.MultiLayerSingleTreeFirstTreeLeafItem);/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeLastTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeLastTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-last-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.last_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_last_tree_leaf_item", BI.MultiLayerSingleTreeLastTreeLeafItem);/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeMidTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeMidTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-mid-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.mid_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_mid_tree_leaf_item", BI.MultiLayerSingleTreeMidTreeLeafItem);/**
+ *
+ * @class BI.MultiSelectCheckPane
+ * @extends BI.Widget
+ */
+BI.MultiSelectCheckPane = BI.inherit(BI.Widget, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-check-pane",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            onClickContinueSelect: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.storeValue = {};
+        this.display = BI.createWidget({
+            type: 'bi.display_selected_list',
+            items: opts.items,
+            itemsCreator: function (op, callback) {
+                op = BI.extend(op || {}, {
+                    selected_values: self.storeValue.value
+                });
+                if (self.storeValue.type === BI.Selection.Multi) {
+                    callback({
+                        items: BI.map(self.storeValue.value, function (i, v) {
+                            var txt = opts.valueFormatter(v) || v;
+                            return {
+                                text: txt,
+                                value: v,
+                                title: txt
+                            }
+                        })
+                    });
+                    return;
+                }
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.continueSelect = BI.createWidget({
+            type: 'bi.text_button',
+            text: BI.i18nText('BI-Continue_Select'),
+            cls: 'multi-select-check-selected'
+        });
+
+        this.continueSelect.on(BI.TextButton.EVENT_CHANGE, function () {
+            opts.onClickContinueSelect();
+        });
+
+        BI.createWidget({
+            type: 'bi.vtape',
+            element: this,
+            items: [{
+                height: this.constants.height,
+                el: {
+                    type: 'bi.left',
+                    cls: 'multi-select-continue-select',
+                    items: [
+                        {
+                            el: {
+                                type: "bi.label",
+                                text: BI.i18nText('BI-Selected_Data')
+                            },
+                            lgap: this.constants.lgap,
+                            tgap: this.constants.tgap
+                        },
+                        {
+                            el: this.continueSelect,
+                            lgap: this.constants.lgap,
+                            tgap: this.constants.tgap
+                        }]
+                }
+            }, {
+                height: 'fill',
+                el: this.display
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+    },
+
+    empty: function () {
+        this.display.empty();
+    },
+
+    populate: function () {
+        this.display.populate.apply(this.display, arguments);
+    }
+});
+
+$.shortcut("bi.multi_select_check_pane", BI.MultiSelectCheckPane);/**
+ *
+ *
+ * 查看已选弹出层的展示面板
+ * @class BI.DisplaySelectedList
+ * @extends BI.Widget
+ */
+BI.DisplaySelectedList = BI.inherit(BI.Pane, {
+
+    constants: {
+        height: 25,
+        lgap: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DisplaySelectedList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-display-list",
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.DisplaySelectedList.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.list_pane",
+            element: this,
+            el: {
+                type: "bi.loader",
+                isDefaultInit: false,
+                logic: {
+                    dynamic: true,
+                    scrolly: true
+                },
+                items: this._createItems(opts.items),
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                layouts: [{
+                    type: "bi.vertical",
+                    lgap: 10
+                }]
+            },
+            itemsCreator: function (options, callback) {
+
+                opts.itemsCreator(options, function (ob) {
+                    self.hasNext = !!ob.hasNext;
+                    callback(self._createItems(ob.items));
+                })
+            },
+            hasNext: function () {
+                return self.hasNext;
+            }
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: 'bi.icon_text_item',
+            cls: 'cursor-default check-font display-list-item',
+            once: true,
+            invalid: true,
+            selected: true,
+            height: this.constants.height,
+            logic: {
+                dynamic: true
+            }
+        });
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        if (arguments.length === 0) {
+            this.button_group.populate();
+        } else {
+            this.button_group.populate(this._createItems(items));
+        }
+    }
+});
+
+$.shortcut('bi.display_selected_list', BI.DisplaySelectedList);/**
+ *
+ * @class BI.MultiSelectCombo
+ * @extends BI.Single
+ */
+BI.MultiSelectCombo = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-combo',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            height: 28
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        var assertShowValue = function () {
+            BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue);
+            self.trigger.getSearcher().setState(self.storeValue);
+            self.trigger.getCounter().setButtonChecked(self.storeValue);
+        };
+        this.storeValue = {};
+        this.popup = BI.createWidget({
+            type: 'bi.multi_select_popup_view',
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            onLoaded: function () {
+                BI.nextTick(function () {
+                    self.combo.adjustWidth();
+                    self.combo.adjustHeight();
+                    self.trigger.getCounter().adjustView();
+                    self.trigger.getSearcher().adjustView();
+                });
+            }
+        });
+
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CHANGE, function () {
+            self.storeValue = this.getValue();
+            self._adjust(function () {
+                assertShowValue();
+            });
+        });
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM, function () {
+            self._defaultState();
+        });
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CLICK_CLEAR, function () {
+            self.setValue();
+            self._defaultState();
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: {
+                    left: 1,
+                    top: 1,
+                    right: 2,
+                    bottom: 33
+                }
+            },
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (res) {
+                    if (op.times === 1 && BI.isNotNull(op.keywords)) {
+                        self.trigger.setValue(self.getValue());
+                    }
+                    callback.apply(self, arguments);
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self._setStartValue("");
+            this.getSearcher().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self._setStartValue("");
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_PAUSE, function () {
+            if (this.getSearcher().hasMatched()) {
+                var keyword = this.getSearcher().getKeyword();
+                self._join({
+                    type: BI.Selection.Multi,
+                    value: [keyword]
+                }, function () {
+                    self.combo.setValue(self.storeValue);
+                    self._setStartValue(keyword);
+                    assertShowValue();
+                    self.populate();
+                    self._setStartValue("");
+                })
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_SEARCHING, function (keywords) {
+            var last = BI.last(keywords);
+            keywords = BI.initial(keywords || []);
+            if (keywords.length > 0) {
+                self._joinKeywords(keywords, function () {
+                    if (BI.isEndWithBlank(last)) {
+                        self.combo.setValue(self.storeValue);
+                        assertShowValue();
+                        self.combo.populate();
+                        self._setStartValue("");
+                    } else {
+                        self.combo.setValue(self.storeValue);
+                        assertShowValue();
+                    }
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function (value, obj) {
+            if (obj instanceof BI.MultiSelectBar) {
+                self._joinAll(this.getValue(), function () {
+                    assertShowValue();
+                });
+            } else {
+                self._join(this.getValue(), function () {//安徽省 北京
+                    assertShowValue();
+                });
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            this.getCounter().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: this.popup
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            this.setValue(self.storeValue);
+            BI.nextTick(function () {
+                self.populate();
+            });
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            //important:关闭弹出时又可能没有退出编辑状态
+            self.trigger.stopEditing();
+            self.fireEvent(BI.MultiSelectCombo.EVENT_CONFIRM);
+        });
+
+        var triggerBtn = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: o.height,
+            height: o.height,
+            cls: "multi-select-trigger-icon-button"
+        });
+        triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+            self.trigger.getCounter().hideView();
+            if (self.combo.isViewVisible()) {
+                self.combo.hideView();
+            } else {
+                self.combo.showView();
+            }
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: triggerBtn,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+        this.combo.hideView();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    _makeMap: function (values) {
+        return BI.makeObject(values || []);
+    },
+
+    _joinKeywords: function (keywords, callback) {
+        var self = this, o = this.options;
+        this._assertValue(this.storeValue);
+        o.itemsCreator({
+            type: BI.MultiSelectCombo.REQ_GET_ALL_DATA,
+            keywords: keywords
+        }, function (ob) {
+            var values = BI.pluck(ob.items, "value");
+            digest(values);
+        });
+
+        function digest(items) {
+            var selectedMap = self._makeMap(items);
+            BI.each(keywords, function (i, val) {
+                if (BI.isNotNull(selectedMap[val])) {
+                    self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val);
+                }
+            });
+            self._adjust(callback);
+        }
+    },
+
+    _joinAll: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        o.itemsCreator({
+            type: BI.MultiSelectCombo.REQ_GET_ALL_DATA,
+            keywords: [this.trigger.getKey()]
+        }, function (ob) {
+            var items = BI.pluck(ob.items, "value");
+            if (self.storeValue.type === res.type) {
+                var change = false;
+                var map = self._makeMap(self.storeValue.value);
+                BI.each(items, function (i, v) {
+                    if (BI.isNotNull(map[v])) {
+                        change = true;
+                        delete map[v];
+                    }
+                });
+                change && (self.storeValue.value = BI.values(map));
+                self._adjust(callback);
+                return;
+            }
+            var selectedMap = self._makeMap(self.storeValue.value);
+            var notSelectedMap = self._makeMap(res.value);
+            var newItems = [];
+            BI.each(items, function (i, item) {
+                if (BI.isNotNull(selectedMap[items[i]])) {
+                    delete selectedMap[items[i]];
+                }
+                if (BI.isNull(notSelectedMap[items[i]])) {
+                    newItems.push(item);
+                }
+            });
+            self.storeValue.value = newItems.concat(BI.values(selectedMap));
+            self._adjust(callback);
+        })
+    },
+
+    _adjust: function (callback) {
+        var self = this, o = this.options;
+        if (!this._count) {
+            o.itemsCreator({
+                type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                self._count = res.count;
+                adjust();
+                callback();
+            });
+        } else {
+            adjust();
+            callback();
+        }
+        function adjust() {
+            if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.Multi,
+                    value: []
+                }
+            } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.All,
+                    value: []
+                }
+            }
+        }
+    },
+
+    _join: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        this._assertValue(this.storeValue);
+        if (this.storeValue.type === res.type) {
+            var map = this._makeMap(this.storeValue.value);
+            BI.each(res.value, function (i, v) {
+                if (!map[v]) {
+                    self.storeValue.value.push(v);
+                    map[v] = v;
+                }
+            });
+            var change = false;
+            BI.each(res.assist, function (i, v) {
+                if (BI.isNotNull(map[v])) {
+                    change = true;
+                    delete map[v];
+                }
+            });
+            change && (this.storeValue.value = BI.values(map));
+            self._adjust(callback);
+            return;
+        }
+        this._joinAll(res, callback);
+    },
+
+    _setStartValue: function (value) {
+        this._startValue = value;
+        this.popup.setStartValue(value);
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.combo.setValue(this.storeValue);
+        this.trigger.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.storeValue;
+    },
+
+    populate: function () {
+        this._count = null;
+        this.combo.populate.apply(this.combo, arguments);
+    }
+});
+
+BI.extend(BI.MultiSelectCombo, {
+    REQ_GET_DATA_LENGTH: 0,
+    REQ_GET_ALL_DATA: -1
+});
+
+BI.MultiSelectCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+
+$.shortcut('bi.multi_select_combo', BI.MultiSelectCombo);/**
+ * 多选加载数据面板
+ * Created by guy on 15/11/2.
+ * @class BI.MultiSelectLoader
+ * @extends Widget
+ */
+BI.MultiSelectLoader = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-loader',
+            logic: {
+                dynamic: true
+            },
+            el: {
+                height: 400
+            },
+            valueFormatter: BI.emptyFn,
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectLoader.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+        var hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            logic: opts.logic,
+            el: BI.extend({
+                onLoaded: opts.onLoaded,
+                el: {
+                    type: "bi.loader",
+                    isDefaultInit: false,
+                    logic: {
+                        dynamic: true,
+                        scrolly: true
+                    },
+                    el: {
+                        chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                        behaviors: {
+                            redmark: function () {
+                                return true;
+                            }
+                        },
+                        layouts: [{
+                            type: "bi.vertical"
+                        }]
+                    }
+                }
+            }, opts.el),
+            itemsCreator: function (op, callback) {
+                var startValue = self._startValue;
+                self.storeValue && (op = BI.extend(op || {}, {
+                    selected_values: BI.isKey(startValue) && self.storeValue.type === BI.Selection.Multi
+                        ? self.storeValue.value.concat(startValue) : self.storeValue.value
+                }));
+                opts.itemsCreator(op, function (ob) {
+                    hasNext = ob.hasNext;
+                    var firstItems = [];
+                    if (op.times === 1 && self.storeValue) {
+                        var json = BI.map(self.storeValue.value, function (i, v) {
+                            var txt = opts.valueFormatter(v) || v;
+                            return {
+                                text: txt,
+                                value: v,
+                                title: txt,
+                                selected: self.storeValue.type === BI.Selection.Multi
+                            }
+                        });
+                        if (BI.isKey(self._startValue) && !self.storeValue.value.contains(self._startValue)) {
+                            var txt = opts.valueFormatter(startValue) || startValue;
+                            json.unshift({
+                                text: txt,
+                                value: startValue,
+                                title: txt,
+                                selected: true
+                            })
+                        }
+                        firstItems = self._createItems(json);
+                    }
+                    callback(firstItems.concat(self._createItems(ob.items)), ob.keyword || "");
+                    if (op.times === 1 && self.storeValue) {
+                        BI.isKey(startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](startValue);
+                        self.setValue(self.storeValue);
+                    }
+                    (op.times === 1) && self._scrollToTop();
+                });
+            },
+            hasNext: function () {
+                return hasNext;
+            }
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.SelectList.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectLoader.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            logic: this.options.logic,
+            height: 25,
+            selected: this.isAllSelected()
+        })
+    },
+
+    _scrollToTop: function () {
+        var self = this;
+        BI.delay(function () {
+            self.button_group.element.scrollTop(0);
+        }, 30);
+    },
+
+    isAllSelected: function () {
+        return this.button_group.isAllSelected();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    setStartValue: function (v) {
+        this._startValue = v;
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.button_group.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.button_group.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.button_group.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.button_group.resetWidth(w);
+    }
+});
+
+BI.MultiSelectLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_loader', BI.MultiSelectLoader);/**
+ * 带加载的多选下拉面板
+ * @class BI.MultiSelectPopupView
+ * @extends Widget
+ */
+BI.MultiSelectPopupView = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-popup-view',
+            maxWidth: 'auto',
+            minWidth: 135,
+            maxHeight: 400,
+            valueFormatter: BI.emptyFn,
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectPopupView.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+
+        this.loader = BI.createWidget({
+            type: "bi.multi_select_loader",
+            itemsCreator: opts.itemsCreator,
+            valueFormatter: opts.valueFormatter,
+            onLoaded: opts.onLoaded
+        });
+
+        this.popupView = BI.createWidget({
+            type: "bi.multi_popup_view",
+            stopPropagation: false,
+            maxWidth: opts.maxWidth,
+            minWidth: opts.minWidth,
+            maxHeight: opts.maxHeight,
+            element: this,
+            buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')],
+            el: this.loader
+        });
+
+        this.popupView.on(BI.MultiPopupView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectPopupView.EVENT_CHANGE);
+        });
+        this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CLEAR);
+                    break;
+                case 1:
+                    self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM);
+                    break;
+            }
+        });
+    },
+
+    isAllSelected: function () {
+        return this.loader.isAllSelected();
+    },
+
+    setStartValue: function (v) {
+        this.loader.setStartValue(v);
+    },
+
+    setValue: function (v) {
+        this.popupView.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popupView.getValue();
+    },
+
+    populate: function (items) {
+        this.popupView.populate.apply(this.popupView, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.popupView.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.popupView.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.popupView.resetWidth(w);
+    }
+});
+
+BI.MultiSelectPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiSelectPopupView.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+
+
+$.shortcut('bi.multi_select_popup_view', BI.MultiSelectPopupView);/**
+ *
+ * 复选下拉框
+ * @class BI.MultiSelectTrigger
+ * @extends BI.Trigger
+ */
+
+BI.MultiSelectTrigger = BI.inherit(BI.Trigger, {
+
+    constants: {
+        height: 14,
+        rgap: 4,
+        lgap: 4
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-trigger",
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            searcher: {},
+            switcher: {},
+
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectTrigger.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+        if (o.height) {
+            this.setHeight(o.height - 2);
+        }
+
+        this.searcher = BI.createWidget(o.searcher, {
+            type: "bi.multi_select_searcher",
+            height: o.height,
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            popup: {},
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_START);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_PAUSE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_SEARCHING, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_SEARCHING, arguments);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_STOP);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_CHANGE, arguments);
+        });
+        this.numberCounter = BI.createWidget(o.switcher, {
+            type: 'bi.multi_select_check_selected_switcher',
+            valueFormatter: o.valueFormatter,
+            itemsCreator: o.itemsCreator,
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK);
+        });
+        this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW);
+        });
+
+        var wrapNumberCounter = BI.createWidget({
+            type: 'bi.right_vertical_adapt',
+            hgap: 4,
+            items: [{
+                el: this.numberCounter
+            }]
+        });
+
+        var wrapper = BI.createWidget({
+            type: 'bi.htape',
+            element: this,
+            items: [
+                {
+                    el: this.searcher,
+                    width: 'fill'
+                }, {
+                    el: wrapNumberCounter,
+                    width: 0
+                }, {
+                    el: BI.createWidget(),
+                    width: 30
+                }]
+        });
+
+        this.numberCounter.on(BI.Events.VIEW, function (b) {
+            BI.nextTick(function () {//自动调整宽度
+                wrapper.attr("items")[1].width = (b === true ? self.numberCounter.element.outerWidth() + 8 : 0);
+                wrapper.resize();
+            });
+        });
+
+        this.element.click(function (e) {
+            if (self.element.__isMouseInBounds__(e) && !self.numberCounter.element.__isMouseInBounds__(e)) {
+                self.numberCounter.hideView();
+            }
+        });
+    },
+
+    getCounter: function () {
+        return this.numberCounter;
+    },
+
+    getSearcher: function () {
+        return this.searcher;
+    },
+
+    stopEditing: function () {
+        this.searcher.stopSearch();
+        this.numberCounter.hideView();
+    },
+
+    setValue: function (ob) {
+        this.searcher.setValue(ob);
+        this.numberCounter.setValue(ob);
+    },
+
+    setEnable: function (v) {
+        this.searcher.setEnable(v);
+    },
+
+    getKey: function () {
+        return this.searcher.getKey();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    }
+});
+
+BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK";
+BI.MultiSelectTrigger.EVENT_COUNTER_CLICK = "EVENT_COUNTER_CLICK";
+BI.MultiSelectTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectTrigger.EVENT_START = "EVENT_START";
+BI.MultiSelectTrigger.EVENT_STOP = "EVENT_STOP";
+BI.MultiSelectTrigger.EVENT_PAUSE = "EVENT_PAUSE";
+BI.MultiSelectTrigger.EVENT_SEARCHING = "EVENT_SEARCHING";
+BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW = "EVENT_BEFORE_COUNTER_POPUPVIEW";
+
+$.shortcut('bi.multi_select_trigger', BI.MultiSelectTrigger);/**
+ * 多选加载数据搜索loader面板
+ * Created by guy on 15/11/4.
+ * @class BI.MultiSelectSearchLoader
+ * @extends Widget
+ */
+BI.MultiSelectSearchLoader = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearchLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-search-loader',
+            itemsCreator: BI.emptyFn,
+            keywordGetter: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearchLoader.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+        var hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            logic: {
+                dynamic: false
+            },
+            el: {
+                tipText: BI.i18nText("BI-No_Select"),
+                el: {
+                    type: "bi.loader",
+                    isDefaultInit: false,
+                    logic: {
+                        dynamic: true,
+                        scrolly: true
+                    },
+                    el: {
+                        chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                        behaviors: {
+                            redmark: function () {
+                                return true;
+                            }
+                        },
+                        layouts: [{
+                            type: "bi.vertical"
+                        }]
+                    }
+                }
+            },
+            itemsCreator: function (op, callback) {
+                self.storeValue && (op = BI.extend(op || {}, {
+                    selected_values: self.storeValue.value
+                }));
+                opts.itemsCreator(op, function (ob) {
+                    var keyword = ob.keyword = opts.keywordGetter();
+                    hasNext = ob.hasNext;
+                    var firstItems = [];
+                    if (op.times === 1 && self.storeValue) {
+                        var json = self._filterValues(self.storeValue);
+                        firstItems = self._createItems(json);
+                    }
+                    callback(firstItems.concat(self._createItems(ob.items)), keyword);
+                    if (op.times === 1 && self.storeValue) {
+                        self.setValue(self.storeValue);
+                    }
+                });
+            },
+            hasNext: function () {
+                return hasNext;
+            }
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.SelectList.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectSearchLoader.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            logic: {
+                dynamic: false
+            },
+            height: 25,
+            selected: this.isAllSelected()
+        })
+    },
+
+    isAllSelected: function () {
+        return this.button_group.isAllSelected();
+    },
+
+    _filterValues: function (src) {
+        var o = this.options;
+        var keyword = o.keywordGetter();
+        var values = BI.deepClone(src.value) || [];
+        var newValues = BI.map(values, function (i, v) {
+            return {
+                text: o.valueFormatter(v) || v,
+                value: v
+            };
+        });
+        if (BI.isKey(keyword)) {
+            var search = BI.Func.getSearchResult(newValues, keyword);
+            values = search.matched.concat(search.finded);
+        }
+        return BI.map(values, function (i, v) {
+            return {
+                text: v.text,
+                title: v.text,
+                value: v.value,
+                selected: src.type === BI.Selection.All
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.storeValue = v;
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.button_group.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.button_group.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.button_group.resetWidth(w);
+    }
+});
+
+BI.MultiSelectSearchLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_search_loader', BI.MultiSelectSearchLoader);/**
+ *
+ * 在搜索框中输入文本弹出的面板
+ * @class BI.MultiSelectSearchPane
+ * @extends Widget
+ */
+
+BI.MultiSelectSearchPane = BI.inherit(BI.Widget, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearchPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-search-pane",
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            keywordGetter: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearchPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.tooltipClick = BI.createWidget({
+            type: "bi.label",
+            invisible: true,
+            text: BI.i18nText('BI-Click_Blank_To_Select'),
+            cls: 'multi-select-toolbar',
+            height: this.constants.height
+        });
+
+        this.loader = BI.createWidget({
+            type: "bi.multi_select_search_loader",
+            keywordGetter: o.keywordGetter,
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator.apply(self, [op, function (res) {
+                    callback(res);
+                    self.setKeyword(o.keywordGetter());
+                }]);
+            }
+        });
+        this.loader.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.resizer = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.tooltipClick,
+                height: 0
+            }, {
+                el: this.loader
+            }]
+        });
+        this.tooltipClick.setVisible(false);
+    },
+
+    setKeyword: function (keyword) {
+        var btn;
+        var isVisible = this.loader.getAllButtons().length > 0 && (btn = this.loader.getAllButtons()[0]) && (keyword === btn.getValue());
+        if (isVisible !== this.tooltipClick.isVisible()) {
+            this.tooltipClick.setVisible(isVisible);
+            this.resizer.attr("items")[0].height = (isVisible ? this.constants.height : 0);
+            this.resizer.resize();
+        }
+    },
+
+    isAllSelected: function () {
+        return this.loader.isAllSelected();
+    },
+
+    hasMatched: function () {
+        return this.tooltipClick.isVisible();
+    },
+
+    setValue: function (v) {
+        this.loader.setValue(v);
+    },
+
+    getValue: function () {
+        return this.loader.getValue();
+    },
+
+    empty: function () {
+        this.loader.empty();
+    },
+
+    populate: function (items) {
+        this.loader.populate.apply(this.loader, arguments);
+    }
+});
+
+BI.MultiSelectSearchPane.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multi_select_search_pane", BI.MultiSelectSearchPane);/**
+ * 查看已选按钮
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectCheckSelectedButton
+ * @extends BI.Single
+ */
+BI.MultiSelectCheckSelectedButton = BI.inherit(BI.Single, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-check-selected-button',
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckSelectedButton.superclass._init.apply(this, arguments);
+        var self = this;
+        this.numberCounter = BI.createWidget({
+            type: 'bi.text_button',
+            element: this,
+            hgap: 4,
+            text: "0",
+            textAlign: 'center',
+            textHeight: 15
+        });
+        this.numberCounter.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.numberCounter.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments);
+        });
+
+        this.numberCounter.element.hover(function () {
+            self.numberCounter.setTag(self.numberCounter.getText());
+            self.numberCounter.setText(self._const.checkSelected);
+        }, function () {
+            self.numberCounter.setText(self.numberCounter.getTag());
+        });
+        this.setVisible(false);
+    },
+
+    setValue: function (ob) {
+        var self = this, o = this.options;
+        ob || (ob = {});
+        ob.type || (ob.type = BI.Selection.Multi);
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            o.itemsCreator({
+                type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                var length = res.count - ob.value.length;
+                BI.nextTick(function(){
+                    self.numberCounter.setText(length);
+                    self.setVisible(length > 0);
+                });
+            });
+            return;
+        }
+        BI.nextTick(function(){
+            self.numberCounter.setText(ob.value.length);
+            self.setVisible(ob.value.length > 0);
+        })
+    },
+
+    getValue: function () {
+
+    }
+});
+
+BI.MultiSelectCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_check_selected_button', BI.MultiSelectCheckSelectedButton);/**
+ * 多选输入框
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectEditor
+ * @extends Widget
+ */
+BI.MultiSelectEditor = BI.inherit(BI.Widget, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectEditor.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-editor',
+            el: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget(o.el, {
+            type: 'bi.state_editor',
+            element: this,
+            height: o.height,
+            watermark: BI.i18nText('BI-Basic_Search'),
+            allowBlank: true
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.StateEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.MultiSelectEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.StateEditor.EVENT_CLICK_LABEL, function () {
+
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    setState: function (state) {
+        this.editor.setState(state);
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+    },
+
+    setEnable: function(v){
+        this.editor.setEnable(v);
+    },
+
+    getValue: function () {
+        var v = this.editor.getState();
+        if (BI.isArray(v) && v.length > 0) {
+            return v[v.length - 1];
+        } else {
+            return "";
+        }
+    },
+
+    getKeywords: function () {
+        var val = this.editor.getLastValidValue();
+        var keywords = val.match(/[\S]+/g);
+        if (BI.isEndWithBlank(val)) {
+            return keywords.concat([' ']);
+        }
+        return keywords;
+    },
+
+    populate: function (items) {
+
+    }
+});
+BI.MultiSelectEditor.EVENT_PAUSE = "MultiSelectEditor.EVENT_PAUSE";
+$.shortcut('bi.multi_select_editor', BI.MultiSelectEditor);/**
+ * searcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectSearcher
+ * @extends Widget
+ */
+BI.MultiSelectSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-searcher',
+            itemsCreator: BI.emptyFn,
+            el: {},
+            popup: {},
+            valueFormatter: BI.emptyFn,
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget(o.el, {
+            type: 'bi.multi_select_editor',
+            height: o.height
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            element: this,
+            height: o.height,
+            isAutoSearch: false,
+            isAutoSync: false,
+            onSearch: function (op, callback) {
+                callback();
+            },
+            el: this.editor,
+
+            popup: BI.extend({
+                type: "bi.multi_select_search_pane",
+                valueFormatter: o.valueFormatter,
+                keywordGetter: function () {
+                    return self.editor.getValue();
+                },
+                itemsCreator: function (op, callback) {
+                    op.keyword = self.editor.getValue();
+                    this.setKeyword(op.keyword);
+                    o.itemsCreator(op, callback);
+                }
+            }, o.popup),
+
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.Searcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_START);
+        });
+        this.searcher.on(BI.Searcher.EVENT_PAUSE, function () {
+            if (this.hasMatched()) {
+
+            }
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.Searcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_STOP);
+        });
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_CHANGE, arguments);
+        });
+        this.searcher.on(BI.Searcher.EVENT_SEARCHING, function () {
+            var keywords = this.getKeywords();
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_SEARCHING, keywords);
+        });
+    },
+
+    adjustView: function () {
+        this.searcher.adjustView();
+    },
+
+    isSearching: function () {
+        return this.searcher.isSearching();
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    getKeyword: function () {
+        return this.editor.getValue();
+    },
+
+    hasMatched: function () {
+        return this.searcher.hasMatched();
+    },
+
+    hasChecked: function () {
+        return this.searcher.getView() && this.searcher.getView().hasChecked();
+    },
+
+    setState: function (ob) {
+        ob || (ob = {});
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All);
+        } else {
+            if (BI.size(ob.value) === 1) {
+                this.editor.setState(ob.value[0] + "");
+            } else {
+                this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None);
+            }
+        }
+    },
+
+    setValue: function (ob) {
+        this.setState(ob);
+        this.searcher.setValue(ob);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    setEnable: function (v) {
+        this.editor.setEnable(v);
+    },
+
+    populate: function (items) {
+        this.searcher.populate.apply(this.searcher, arguments);
+    }
+});
+
+BI.MultiSelectSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.MultiSelectSearcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectSearcher.EVENT_START = "EVENT_START";
+BI.MultiSelectSearcher.EVENT_STOP = "EVENT_STOP";
+BI.MultiSelectSearcher.EVENT_PAUSE = "EVENT_PAUSE";
+BI.MultiSelectSearcher.EVENT_SEARCHING = "EVENT_SEARCHING";
+$.shortcut('bi.multi_select_searcher', BI.MultiSelectSearcher);/**
+ * 查看已选switcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectCheckSelectedSwitcher
+ * @extends Widget
+ */
+BI.MultiSelectCheckSelectedSwitcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckSelectedSwitcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-check-selected-switcher',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            el: {},
+            popup: {},
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckSelectedSwitcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget(o.el, {
+            type: "bi.multi_select_check_selected_button",
+            itemsCreator: o.itemsCreator
+        });
+        this.button.on(BI.Events.VIEW, function () {
+            self.fireEvent(BI.Events.VIEW, arguments);
+        });
+        this.switcher = BI.createWidget({
+            type: "bi.switcher",
+            toggle: false,
+            element: this,
+            el: this.button,
+            popup: BI.extend({
+                type: "bi.multi_select_check_pane",
+                valueFormatter: o.valueFormatter,
+                itemsCreator: o.itemsCreator,
+                onClickContinueSelect: function () {
+                    self.switcher.hideView();
+                }
+            }, o.popup),
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.switcher.on(BI.Switcher.EVENT_TRIGGER_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE);
+        });
+        this.switcher.on(BI.Switcher.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.switcher.on(BI.Switcher.EVENT_AFTER_POPUPVIEW, function () {
+            var me = this;
+            BI.nextTick(function () {
+                me.populate();
+            });
+        });
+
+        this.switcher.element.click(function (e) {
+            e.stopPropagation();
+        });
+    },
+
+    adjustView: function () {
+        this.switcher.adjustView();
+    },
+
+    hideView: function () {
+        this.switcher.empty();
+        this.switcher.hideView();
+    },
+
+    setValue: function (v) {
+        this.switcher.setValue(v);
+    },
+
+    setButtonChecked: function (v) {
+        this.button.setValue(v)
+    },
+
+    getValue: function () {
+
+    },
+
+    populate: function (items) {
+        this.switcher.populate.apply(this.switcher, arguments);
+    }
+});
+
+BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE = "MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE";
+BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW = "MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW";
+$.shortcut('bi.multi_select_check_selected_switcher', BI.MultiSelectCheckSelectedSwitcher);/**
+ * Created by zcf on 2016/12/14.
+ */
+BI.MultiStringList = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiStringList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-string-list',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiStringList.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        var assertShowValue = function () {
+            BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue);
+            self.trigger.getSearcher().setState(self.storeValue);
+            self.trigger.getCounter().setButtonChecked(self.storeValue);
+        };
+        this.storeValue = {};
+
+
+        this.popup = BI.createWidget({
+            type: "bi.multi_select_loader",
+            cls: "popup-multi-string-list",
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            onLoaded: o.onLoaded,
+            el: {
+                height: ""
+            }
+        });
+        this.popup.on(BI.MultiSelectLoader.EVENT_CHANGE, function () {
+            self.storeValue = this.getValue();
+            self._adjust(function () {
+                assertShowValue();
+                self.fireEvent(BI.MultiStringList.EVENT_CHANGE);
+            });
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: {
+                    left: 1,
+                    top: 0,
+                    right: 2,
+                    bottom: 1
+                }
+            },
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (res) {
+                    if (op.times === 1 && BI.isNotNull(op.keyword)) {
+                        self.trigger.setValue(self.getValue());
+                    }
+                    callback.apply(self, arguments);
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self._setStartValue("");
+            this.getSearcher().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self._setStartValue("");
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_PAUSE, function () {
+            if (this.getSearcher().hasMatched()) {
+                var keyword = this.getSearcher().getKeyword();
+                self._join({
+                    type: BI.Selection.Multi,
+                    value: [keyword]
+                }, function () {
+                    self.trigger.setValue(self.storeValue);
+                    self.popup.setValue(self.storeValue);
+                    self._setStartValue(keyword);
+                    assertShowValue();
+                    self.populate();
+                    self._setStartValue("");
+                    self.fireEvent(BI.MultiStringList.EVENT_CHANGE);
+                })
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_SEARCHING, function (keywords) {
+            var last = BI.last(keywords);
+            keywords = BI.initial(keywords || []);
+            if (keywords.length > 0) {
+                self._joinKeywords(keywords, function () {
+                    if (BI.isEndWithBlank(last)) {
+                        self.trigger.setValue(self.storeValue);
+                        self.popup.setValue(self.storeValue);
+                        assertShowValue();
+                        self.popup.populate();
+                        self._setStartValue("");
+                    } else {
+                        self.trigger.setValue(self.storeValue);
+                        self.popup.setValue(self.storeValue);
+                        assertShowValue();
+                    }
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function (value, obj) {
+            if (obj instanceof BI.MultiSelectBar) {
+                self._joinAll(this.getValue(), function () {
+                    assertShowValue();
+                });
+            } else {
+                self._join(this.getValue(), function () {//安徽省 北京
+                    assertShowValue();
+                });
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            this.getCounter().setValue(self.storeValue);
+        });
+        var div = BI.createWidget({
+            type: "bi.layout"
+        });
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            height: "100%",
+            width: "100%",
+            items: [{
+                el: this.trigger,
+                height: 25
+            }, {
+                el: div,
+                height: 2
+            }, {
+                el: this.popup,
+                height: "fill"
+            }]
+        });
+    },
+    _defaultState: function () {
+        this.trigger.stopEditing();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    _makeMap: function (values) {
+        return BI.makeObject(values || []);
+    },
+
+    _joinKeywords: function (keywords, callback) {
+        var self = this, o = this.options;
+        this._assertValue(this.storeValue);
+        if (!this._allData) {
+            o.itemsCreator({
+                type: BI.MultiStringList.REQ_GET_ALL_DATA
+            }, function (ob) {
+                self._allData = BI.pluck(ob.items, "value");
+                digest(self._allData);
+            })
+        } else {
+            digest(this._allData)
+        }
+
+        function digest(items) {
+            var selectedMap = self._makeMap(items);
+            BI.each(keywords, function (i, val) {
+                if (BI.isNotNull(selectedMap[val])) {
+                    self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val);
+                }
+            });
+            self._adjust(callback);
+        }
+    },
+
+    _joinAll: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        o.itemsCreator({
+            type: BI.MultiStringList.REQ_GET_ALL_DATA,
+            keyword: this.trigger.getKey()
+        }, function (ob) {
+            var items = BI.pluck(ob.items, "value");
+            if (self.storeValue.type === res.type) {
+                var change = false;
+                var map = self._makeMap(self.storeValue.value);
+                BI.each(items, function (i, v) {
+                    if (BI.isNotNull(map[v])) {
+                        change = true;
+                        delete map[v];
+                    }
+                });
+                change && (self.storeValue.value = BI.values(map));
+                self._adjust(callback);
+                return;
+            }
+            var selectedMap = self._makeMap(self.storeValue.value);
+            var notSelectedMap = self._makeMap(res.value);
+            var newItems = [];
+            BI.each(items, function (i, item) {
+                if (BI.isNotNull(selectedMap[items[i]])) {
+                    delete selectedMap[items[i]];
+                }
+                if (BI.isNull(notSelectedMap[items[i]])) {
+                    newItems.push(item);
+                }
+            });
+            self.storeValue.value = newItems.concat(BI.values(selectedMap));
+            self._adjust(callback);
+        })
+    },
+
+    _adjust: function (callback) {
+        var self = this, o = this.options;
+        if (!this._count) {
+            o.itemsCreator({
+                type: BI.MultiStringList.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                self._count = res.count;
+                adjust();
+                callback();
+            });
+        } else {
+            adjust();
+            callback();
+        }
+        function adjust() {
+            if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.Multi,
+                    value: []
+                }
+            } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.All,
+                    value: []
+                }
+            }
+        }
+    },
+
+    _join: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        this._assertValue(this.storeValue);
+        if (this.storeValue.type === res.type) {
+            var map = this._makeMap(this.storeValue.value);
+            BI.each(res.value, function (i, v) {
+                if (!map[v]) {
+                    self.storeValue.value.push(v);
+                    map[v] = v;
+                }
+            });
+            var change = false;
+            BI.each(res.assist, function (i, v) {
+                if (BI.isNotNull(map[v])) {
+                    change = true;
+                    delete map[v];
+                }
+            });
+            change && (this.storeValue.value = BI.values(map));
+            self._adjust(callback);
+            return;
+        }
+        this._joinAll(res, callback);
+    },
+
+    _setStartValue: function (value) {
+        this._startValue = value;
+        this.popup.setStartValue(value);
+    },
+
+    // isAllSelected: function () {
+    //     return this.popup.isAllSelected();
+    // },
+
+    resize: function () {
+        this.trigger.getCounter().adjustView();
+        this.trigger.getSearcher().adjustView();
+    },
+
+    setEnable: function (v) {
+        this.trigger.setEnable(v);
+        this.popup.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.popup.setValue(this.storeValue);
+        this.trigger.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.storeValue;
+    },
+
+    populate: function () {
+        this._count = null;
+        this._allData = null;
+        this.popup.populate.apply(this.popup, arguments);
+        this.trigger.populate.apply(this.trigger, arguments);
+    }
+});
+
+BI.extend(BI.MultiStringList, {
+    REQ_GET_DATA_LENGTH: 0,
+    REQ_GET_ALL_DATA: -1
+});
+
+BI.MultiStringList.EVENT_CHANGE = "BI.MultiStringList.EVENT_CHANGE";
+$.shortcut("bi.multi_string_list", BI.MultiStringList);/**
+ *
+ * @class BI.MultiTreeCheckPane
+ * @extends BI.Pane
+ */
+BI.MultiTreeCheckPane = BI.inherit(BI.Pane, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-tree-check-pane",
+            onClickContinueSelect: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCheckPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.selected_values = {};
+
+        var continueSelect = BI.createWidget({
+            type: 'bi.text_button',
+            text: BI.i18nText('BI-Continue_Select'),
+            cls: 'multi-tree-check-selected'
+        });
+        continueSelect.on(BI.TextButton.EVENT_CHANGE, function () {
+            opts.onClickContinueSelect();
+            BI.nextTick(function () {
+                self.empty();
+            });
+        });
+
+        var backToPopup = BI.createWidget({
+            type: 'bi.left',
+            cls: 'multi-tree-continue-select',
+            items: [
+                {
+                    el: {
+                        type: "bi.label",
+                        text: BI.i18nText('BI-Selected_Data')
+                    },
+                    lgap: this.constants.lgap,
+                    tgap: this.constants.tgap
+                },
+                {
+                    el: continueSelect,
+                    lgap: this.constants.lgap,
+                    tgap: this.constants.tgap
+                }]
+        });
+
+        this.display = BI.createWidget({
+            type: "bi.display_tree",
+            cls: "bi-multi-tree-display",
+            itemsCreator: function (op, callback) {
+                op.type = BI.TreeView.REQ_TYPE_SELECTED_DATA;
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.display.on(BI.Events.AFTERINIT, function () {
+            self.fireEvent(BI.Events.AFTERINIT);
+        });
+
+        this.display.on(BI.TreeView.EVENT_INIT, function () {
+            backToPopup.setVisible(false);
+        });
+
+        this.display.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            backToPopup.setVisible(true);
+        });
+
+        BI.createWidget({
+            type: 'bi.vtape',
+            element: this,
+            items: [{
+                height: this.constants.height,
+                el: backToPopup
+            }, {
+                height: 'fill',
+                el: this.display
+            }]
+        });
+
+    },
+
+    empty: function () {
+        this.display.empty();
+    },
+
+    populate: function (configs) {
+        this.display.stroke(configs);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.display.setValue(v.value);
+    },
+
+    getValue: function () {
+
+    }
+});
+
+BI.MultiTreeCheckPane.EVENT_CONTINUE_CLICK = "EVENT_CONTINUE_CLICK";
+
+
+$.shortcut("bi.multi_tree_check_pane", BI.MultiTreeCheckPane);/**
+ *
+ * @class BI.MultiTreeCombo
+ * @extends BI.Single
+ */
+
+BI.MultiTreeCombo = BI.inherit(BI.Single, {
+
+    constants: {
+        offset: {
+            top: 1,
+            left: 1,
+            right: 2,
+            bottom: 33
+        }
+    },
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-combo',
+            itemsCreator: BI.emptyFn,
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCombo.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.popup = BI.createWidget({
+            type: 'bi.multi_tree_popup_view',
+            itemsCreator: o.itemsCreator,
+            onLoaded: function () {
+                BI.nextTick(function () {
+                    self.trigger.getCounter().adjustView();
+                    self.trigger.getSearcher().adjustView();
+                });
+            }
+        });
+        var isInit = false;
+        var want2showCounter = false;
+
+        this.popup.on(BI.MultiTreePopup.EVENT_AFTERINIT, function () {
+            self.trigger.getCounter().adjustView();
+            isInit = true;
+            if (want2showCounter === true) {
+                showCounter();
+            }
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: this.constants.offset
+            },
+            searcher: {
+                type: "bi.multi_tree_searcher",
+                itemsCreator: o.itemsCreator
+            },
+            switcher: {
+                el: {
+                    type: "bi.multi_tree_check_selected_button"
+                },
+                popup: {
+                    type: "bi.multi_tree_check_pane",
+                    itemsCreator: o.itemsCreator
+                }
+            }
+
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: this.popup
+        });
+
+        this.storeValue = {value: {}};
+        var change = false;
+        var clear = false;          //标识当前是否点击了清空
+
+        var isSearching = function () {
+            return self.trigger.getSearcher().isSearching();
+        };
+
+        var isPopupView = function () {
+            return self.combo.isViewVisible();
+        };
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self.storeValue = {value: self.combo.getValue()};
+            this.setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self.storeValue = {value: this.getValue()};
+            self.combo.setValue(self.storeValue);
+            BI.nextTick(function () {
+                if (isPopupView()) {
+                    self.combo.populate();
+                }
+            });
+        });
+        function showCounter() {
+            if (isSearching()) {
+                self.storeValue = {value: self.trigger.getValue()};
+            } else if (isPopupView()) {
+                self.storeValue = {value: self.combo.getValue()};
+            }
+            self.trigger.setValue(self.storeValue);
+        }
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            if (want2showCounter === false) {
+                want2showCounter = true;
+            }
+            if (isInit === true) {
+                want2showCounter = null;
+                showCounter();
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () {
+            self.combo.toggle();
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () {
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.getSearcher().hasChecked() ? {1: 1} : {}
+            };
+            this.getSearcher().setState(val);
+            this.getCounter().setButtonChecked(val);
+        });
+        this.popup.on(BI.MultiTreePopup.EVENT_CHANGE, function () {
+            change = true;
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.hasChecked() ? {1: 1} : {}
+            };
+            self.trigger.getSearcher().setState(val);
+            self.trigger.getCounter().setButtonChecked(val);
+        });
+
+        this.popup.on(BI.MultiTreePopup.EVENT_CLICK_CONFIRM, function () {
+            self._defaultState();
+        });
+        this.popup.on(BI.MultiTreePopup.EVENT_CLICK_CLEAR, function () {
+            clear = true;
+            self.setValue();
+            self._defaultState();
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            if (isSearching()) {
+                return;
+            }
+            if (change === true) {
+                self.storeValue = {value: self.combo.getValue()};
+                change = false;
+            }
+            self.combo.setValue(self.storeValue);
+            self.populate();
+
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () {
+            if (isSearching()) {
+                self.trigger.stopEditing();
+                self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM);
+                return;
+            }
+            if (isPopupView()) {
+                self.trigger.stopEditing();
+                self.storeValue = {value: self.combo.getValue()};
+                if (clear === true) {
+                    self.storeValue = {value: {}};
+                    clear = false;
+                    change = false;
+                }
+                self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM);
+            }
+        });
+
+        var triggerBtn = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: o.height,
+            height: o.height,
+            cls: "multi-select-trigger-icon-button"
+        });
+        triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+            self.trigger.getCounter().hideView();
+            if (self.combo.isViewVisible()) {
+                self.combo.hideView();
+            } else {
+                self.combo.showView();
+            }
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: triggerBtn,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+        this.combo.hideView();
+    },
+
+    setEnable: function(v){
+        this.combo.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue.value = v || {};
+        this.combo.setValue({
+            value: v || {}
+        });
+    },
+
+    getValue: function () {
+        return this.storeValue.value;
+    },
+
+    populate: function () {
+        this.combo.populate.apply(this.combo, arguments);
+    }
+});
+
+BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM";
+
+$.shortcut('bi.multi_tree_combo', BI.MultiTreeCombo);/**
+ * 带加载的多选下拉面板
+ * @class BI.MultiTreePopup
+ * @extends BI.Pane
+ */
+BI.MultiTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-popup',
+            maxWidth: 'auto',
+            minWidth: 100,
+            maxHeight: 250,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.selected_values = {};
+
+        this.tree = BI.createWidget({
+            type: "bi.sync_tree",
+            height: 400,
+            cls:"popup-view-tree",
+            itemsCreator: opts.itemsCreator,
+            onLoaded: opts.onLoaded
+        });
+
+        this.popupView = BI.createWidget({
+            type: "bi.multi_popup_view",
+            element: this,
+            stopPropagation: false,
+            maxWidth: opts.maxWidth,
+            minWidth: opts.minWidth,
+            maxHeight: opts.maxHeight,
+            buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')],
+            el: this.tree
+        });
+
+        this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR);
+                    break;
+                case 1:
+                    self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM);
+                    break;
+            }
+        });
+
+        this.tree.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE);
+        });
+
+        this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT);
+        });
+
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.tree.setSelectedValue(v.value);
+    },
+
+    populate: function (config) {
+        this.tree.stroke(config);
+    },
+
+    hasChecked: function () {
+        return this.tree.hasChecked();
+    },
+
+    setEnable: function (arg) {
+        this.popupView.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.popupView.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.popupView.resetWidth(w);
+    }
+});
+
+BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT";
+
+
+$.shortcut('bi.multi_tree_popup_view', BI.MultiTreePopup);/**
+ *
+ * 在搜索框中输入文本弹出的面板
+ * @class BI.MultiTreeSearchPane
+ * @extends BI.Pane
+ */
+
+BI.MultiTreeSearchPane = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-tree-search-pane",
+            itemsCreator: BI.emptyFn,
+            keywordGetter: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeSearchPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.partTree = BI.createWidget({
+            type: "bi.part_tree",
+            element: this,
+            tipText: BI.i18nText("BI-No_Select"),
+            itemsCreator: function (op, callback) {
+                op.keyword = opts.keywordGetter();
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.partTree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.partTree.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE);
+        });
+    },
+
+    hasChecked: function () {
+        return this.partTree.hasChecked();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.partTree.setSelectedValue(v.value);
+    },
+
+    getValue: function () {
+        return this.partTree.getValue();
+    },
+
+    empty: function () {
+        this.partTree.empty();
+    },
+
+    populate: function (op) {
+        this.partTree.stroke.apply(this.partTree, arguments);
+    }
+});
+
+BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE";
+
+BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+
+$.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/**
+ * 查看已选按钮
+ * Created by guy on 15/11/3.
+ * @class BI.MultiTreeCheckSelectedButton
+ * @extends BI.Single
+ */
+BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-check-selected-button',
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments);
+        var self = this;
+        this.indicator = BI.createWidget({
+            type: 'bi.icon_button',
+            cls: 'check-font trigger-check-selected',
+            width: 15,
+            height: 15,
+            stopPropagation: true
+        });
+
+        this.checkSelected = BI.createWidget({
+            type: 'bi.text_button',
+            cls: "trigger-check-selected",
+            invisible: true,
+            hgap: 4,
+            text: this._const.checkSelected,
+            textAlign: 'center',
+            textHeight: 15
+        });
+        this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.horizontal",
+            element: this,
+            items: [this.indicator, this.checkSelected]
+        })
+
+        this.element.hover(function () {
+            self.indicator.setVisible(false);
+            self.checkSelected.setVisible(true);
+        }, function () {
+            self.indicator.setVisible(true);
+            self.checkSelected.setVisible(false);
+        });
+        this.setVisible(false);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.setVisible(BI.size(v.value) > 0);
+    }
+});
+
+BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_tree_check_selected_button', BI.MultiTreeCheckSelectedButton);/**
+ * searcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiTreeSearcher
+ * @extends Widget
+ */
+BI.MultiTreeSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-searcher',
+            itemsCreator: BI.emptyFn,
+            popup: {},
+
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: 'bi.multi_select_editor',
+            height: o.height,
+            el: {
+                type: "bi.simple_state_editor",
+                height: o.height
+            }
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            element: this,
+            isAutoSearch: false,
+            isAutoSync: false,
+            onSearch: function (op, callback) {
+                callback({
+                    keyword: self.editor.getValue()
+                });
+            },
+            el: this.editor,
+
+            popup: BI.extend({
+                type: "bi.multi_tree_search_pane",
+                keywordGetter: function () {
+                    return self.editor.getValue();
+                },
+                itemsCreator: function (op, callback) {
+                    op.keyword = self.editor.getValue();
+                    o.itemsCreator(op, callback);
+                }
+            }, o.popup),
+
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.Searcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_START);
+        });
+        this.searcher.on(BI.Searcher.EVENT_PAUSE, function () {
+            if (this.hasMatched()) {
+
+            }
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.Searcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_STOP);
+        });
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_CHANGE, arguments);
+        });
+    },
+
+    adjustView: function () {
+        this.searcher.adjustView();
+    },
+
+    isSearching: function () {
+        return this.searcher.isSearching();
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    getKeyword: function () {
+        return this.editor.getValue();
+    },
+
+    hasMatched: function () {
+        return this.searcher.hasMatched();
+    },
+
+    hasChecked: function () {
+        return this.searcher.getView() && this.searcher.getView().hasChecked();
+    },
+
+    setState: function (ob) {
+        ob || (ob = {});
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All);
+        } else {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None);
+        }
+    },
+
+    setValue: function (ob) {
+        this.setState(ob);
+        this.searcher.setValue(ob);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+
+    setEnable: function(v){
+        this.editor.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function (items) {
+        this.searcher.populate.apply(this.searcher, arguments);
+    }
+});
+
+BI.MultiTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.MultiTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiTreeSearcher.EVENT_START = "EVENT_START";
+BI.MultiTreeSearcher.EVENT_STOP = "EVENT_STOP";
+BI.MultiTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE";
+$.shortcut('bi.multi_tree_searcher', BI.MultiTreeSearcher);/**
+ * Created by zcf on 2016/12/20.
+ */
+BI.MultiTreeList = BI.inherit(BI.Widget, {
+    constants: {
+        offset: {
+            left: 1,
+            top: 0,
+            right: 2,
+            bottom: 1
+        }
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-combo',
+            itemsCreator: BI.emptyFn,
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeList.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        var isInit = false;
+        var want2showCounter = false;
+
+        this.popup = BI.createWidget({
+            type: "bi.multi_tree_list_popup",
+            itemsCreator: o.itemsCreator
+        });
+
+        this.popup.on(BI.MultiStringListPopup.EVENT_AFTER_INIT, function () {
+            self.trigger.getCounter().adjustView();
+            isInit = true;
+            if (want2showCounter === true) {
+                showCounter();
+            }
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: this.constants.offset
+            },
+            searcher: {
+                type: "bi.multi_tree_searcher",
+                itemsCreator: o.itemsCreator
+            },
+            switcher: {
+                el: {
+                    type: "bi.multi_tree_check_selected_button"
+                },
+                popup: {
+                    type: "bi.multi_tree_check_pane",
+                    itemsCreator: o.itemsCreator
+                }
+            }
+        });
+
+        this.storeValue = {value: {}};
+
+        var isSearching = function () {
+            return self.trigger.getSearcher().isSearching();
+        };
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self.storeValue = {value: self.popup.getValue()};
+            this.setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self.storeValue = {value: this.getValue()};
+            self.trigger.setValue(self.storeValue);
+            self.popup.setValue(self.storeValue);
+            BI.nextTick(function () {
+                self.trigger.populate();
+                self.popup.populate();
+            });
+        });
+        function showCounter() {
+            if (isSearching()) {
+                self.storeValue = {value: self.trigger.getValue()};
+            } else {
+                self.storeValue = {value: self.popup.getValue()};
+            }
+            self.trigger.setValue(self.storeValue);
+        }
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            if (want2showCounter === false) {
+                want2showCounter = true;
+            }
+            if (isInit === true) {
+                want2showCounter = null;
+                showCounter();
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () {
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.getSearcher().hasChecked() ? {1: 1} : {}
+            };
+            this.getSearcher().setState(val);
+            this.getCounter().setButtonChecked(val);
+        });
+
+        this.popup.on(BI.MultiStringListPopup.EVENT_CHANGE, function () {
+            showCounter();
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.hasChecked() ? {1: 1} : {}
+            };
+            self.trigger.getSearcher().setState(val);
+            self.trigger.getCounter().setButtonChecked(val);
+            self.fireEvent(BI.MultiTreeList.EVENT_CHANGE);
+        });
+
+        var div = BI.createWidget({
+            type: "bi.layout"
+        });
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            height: "100%",
+            width: "100%",
+            items: [{
+                el: this.trigger,
+                height: 25
+            }, {
+                el: div,
+                height: 2
+            }, {
+                el: this.popup,
+                height: "fill"
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+    },
+
+    resize: function () {
+        this.trigger.getCounter().adjustView();
+        this.trigger.getSearcher().adjustView();
+    },
+
+    setEnable: function (v) {
+        this.trigger.setEnable(v);
+        this.popup.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue.value = v || {};
+        this.popup.setValue({
+            value: v || {}
+        });
+        this.trigger.setValue({
+            value: v || {}
+        });
+    },
+
+    getValue: function () {
+        return this.storeValue.value;
+    },
+
+    populate: function () {
+        this.trigger.populate.apply(this.trigger, arguments);
+        this.popup.populate.apply(this.popup, arguments);
+    }
+});
+BI.MultiTreeList.EVENT_CHANGE = "MultiTreeList.EVENT_CHANGE";
+$.shortcut('bi.multi_tree_list', BI.MultiTreeList);/**
+ * Created by zcf on 2016/12/21.
+ */
+BI.MultiStringListPopup=BI.inherit(BI.Widget,{
+    _defaultConfig:function () {
+        return BI.extend(BI.MultiStringListPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-list-popup",
+            itemsCreator: BI.emptyFn
+        });
+    },
+    _init:function () {
+        BI.MultiStringListPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.popup = BI.createWidget({
+            type: "bi.sync_tree",
+            height: 400,
+            element: this,
+            itemsCreator: o.itemsCreator
+        });
+        this.popup.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            self.fireEvent(BI.MultiStringListPopup.EVENT_AFTER_INIT)
+        });
+        this.popup.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiStringListPopup.EVENT_CHANGE)
+        });
+    },
+
+    hasChecked: function () {
+        return this.popup.hasChecked();
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.popup.setValue(v.value);
+    },
+
+    populate: function (config) {
+        this.popup.stroke(config);
+    }
+
+});
+BI.MultiStringListPopup.EVENT_AFTER_INIT="BI.MultiStringListPopup.EVENT_AFTER_INIT";
+BI.MultiStringListPopup.EVENT_CHANGE="BI.MultiStringListPopup.EVENT_CHANGE";
+$.shortcut("bi.multi_tree_list_popup",BI.MultiStringListPopup);//小于号的值为:0,小于等于号的值为:1
+//closeMIn:最小值的符号,closeMax:最大值的符号
+/**
+ * Created by roy on 15/9/17.
+ *
+ */
+BI.NumericalInterval = BI.inherit(BI.Single, {
+    constants: {
+        typeError: "typeBubble",
+        numberError: "numberBubble",
+        signalError: "signalBubble",
+        editorWidth: 114,
+        columns: 5,
+        width: 30,
+        rows: 1,
+        numberErrorCls: "number-error",
+        border: 1,
+        less: 0,
+        less_equal: 1,
+        numTip: ""
+    },
+    _defaultConfig: function () {
+        var conf = BI.NumericalInterval.superclass._defaultConfig.apply(this, arguments)
+        return BI.extend(conf, {
+            extraCls: "bi-numerical-interval",
+            height: 25
+
+        })
+    },
+    _init: function () {
+        var self = this, c = this.constants, o = this.options;
+        BI.NumericalInterval.superclass._init.apply(this, arguments)
+        this.smallEditor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height - 2,
+            watermark: BI.i18nText("BI-Unrestricted"),
+            allowBlank: true,
+            value: o.min,
+            level: "warning",
+            tipType: "warning",
+            quitChecker: function () {
+                return false;
+            },
+            validationChecker: function (v) {
+                if (!BI.isNumeric(v)) {
+                    self.smallEditorBubbleType = c.typeError;
+                    return false;
+                }
+                return true;
+            },
+            cls: "numerical-interval-small-editor"
+        });
+
+        this.smallTip = BI.createWidget({
+            type: "bi.label",
+            text: o.numTip,
+            height: o.height - 2,
+            invisible: true
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.smallEditor.element,
+            items: [{
+                el: this.smallTip,
+                top: 0,
+                right: 5
+            }]
+        });
+
+        this.bigEditor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height - 2,
+            watermark: BI.i18nText("BI-Unrestricted"),
+            allowBlank: true,
+            value: o.max,
+            level: "warning",
+            tipType: "warning",
+            quitChecker: function () {
+                return false;
+            },
+            validationChecker: function (v) {
+                if (!BI.isNumeric(v)) {
+                    self.bigEditorBubbleType = c.typeError;
+                    return false;
+                }
+                return true;
+            },
+            cls: "numerical-interval-big-editor"
+        });
+
+        this.bigTip = BI.createWidget({
+            type: "bi.label",
+            text: o.numTip,
+            height: o.height - 2,
+            invisible: true
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.bigEditor.element,
+            items: [{
+                el: this.bigTip,
+                top: 0,
+                right: 5
+            }]
+        });
+
+        //this.smallCombo = BI.createWidget({
+        //    type: "bi.numerical_interval_combo",
+        //    cls: "numerical-interval-small-combo",
+        //    height: o.height,
+        //    value: o.closemin ? 1 : 0,
+        //    offsetStyle: "left"
+        //});
+        //
+        //this.bigCombo = BI.createWidget({
+        //    type: "bi.numerical_interval_combo",
+        //    cls: "numerical-interval-big-combo",
+        //    height: o.height,
+        //    value: o.closemax ? 1 : 0,
+        //    offsetStyle: "left"
+        //});
+        this.smallCombo = BI.createWidget({
+            type: "bi.icon_combo",
+            cls: "numerical-interval-small-combo",
+            height: o.height - 2,
+            items: [{
+                text: "(" + BI.i18nText("BI-Less_Than") + ")",
+                iconClass: "less-font",
+                value: 0
+            }, {
+                text: "(" + BI.i18nText("BI-Less_And_Equal") + ")",
+                value: 1,
+                iconClass: "less-equal-font"
+            }]
+        });
+        if (o.closemin === true) {
+            this.smallCombo.setValue(1);
+        } else {
+            this.smallCombo.setValue(0);
+        }
+        this.bigCombo = BI.createWidget({
+            type: "bi.icon_combo",
+            cls: "numerical-interval-big-combo",
+            height: o.height - 2,
+            items: [{
+                text: "(" + BI.i18nText("BI-Less_Than") + ")",
+                iconClass: "less-font",
+                value: 0
+            }, {
+                text: "(" + BI.i18nText("BI-Less_And_Equal") + ")",
+                value: 1,
+                iconClass: "less-equal-font"
+            }]
+        });
+        if (o.closemax === true) {
+            this.bigCombo.setValue(1);
+        } else {
+            this.bigCombo.setValue(0);
+        }
+        this.label = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-Value"),
+            textHeight: o.height - c.border * 2,
+            width: c.width - c.border * 2,
+            height: o.height - c.border * 2,
+            level: "warning",
+            tipType: "warning"
+        });
+        this.left = BI.createWidget({
+            type: "bi.htape",
+            items: [{
+                el: self.smallEditor
+            }, {
+                el: self.smallCombo,
+                width: c.width - c.border * 2
+            }]
+
+        });
+        this.right = BI.createWidget({
+            type: "bi.htape",
+            items: [{
+                el: self.bigCombo,
+                width: c.width - c.border * 2
+            }, {
+                el: self.bigEditor
+            }]
+        });
+
+
+        BI.createWidget({
+            element: self,
+            type: "bi.center",
+            hgap: 15,
+            height: o.height,
+            items: [
+                {
+                    type: "bi.absolute",
+                    items: [{
+                        el: self.left,
+                        left: -15,
+                        right: 0,
+                        top: 0,
+                        bottom: 0
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: self.right,
+                        left: 0,
+                        right: -15,
+                        top: 0,
+                        bottom: 0
+                    }]
+                }
+            ]
+        });
+
+        BI.createWidget({
+            element: self,
+            type: "bi.horizontal_auto",
+            items: [
+                self.label
+            ]
+        });
+
+
+        self._setValidEvent(self.bigEditor, c.bigEditor);
+        self._setValidEvent(self.smallEditor, c.smallEditor);
+        self._setErrorEvent(self.bigEditor, c.bigEditor);
+        self._setErrorEvent(self.smallEditor, c.smallEditor);
+        self._setBlurEvent(self.bigEditor);
+        self._setBlurEvent(self.smallEditor);
+        self._setFocusEvent(self.bigEditor);
+        self._setFocusEvent(self.smallEditor);
+        self._setComboValueChangedEvent(self.bigCombo);
+        self._setComboValueChangedEvent(self.smallCombo);
+        self._setEditorValueChangedEvent(self.bigEditor);
+        self._setEditorValueChangedEvent(self.smallEditor);
+    },
+
+    _checkValidation: function () {
+        var self = this, c = this.constants, o = this.options;
+        self._setTitle("");
+        BI.Bubbles.hide(c.typeError);
+        BI.Bubbles.hide(c.numberError);
+        BI.Bubbles.hide(c.signalError);
+        if (!self.smallEditor.isValid() || !self.bigEditor.isValid()) {
+            self.element.removeClass("number-error");
+            o.validation = "invalid";
+            return c.typeError;
+        } else {
+            if (BI.isEmptyString(self.smallEditor.getValue()) || BI.isEmptyString(self.bigEditor.getValue())) {
+                self.element.removeClass("number-error");
+                o.validation = "valid";
+                return "";
+            } else {
+                var smallValue = parseFloat(self.smallEditor.getValue()), bigValue = parseFloat(self.bigEditor.getValue()),
+                    bigComboValue = self.bigCombo.getValue(), smallComboValue = self.smallCombo.getValue();
+                if (bigComboValue[0] === c.less_equal && smallComboValue[0] === c.less_equal) {
+                    if (smallValue > bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.numberError;
+                    } else {
+                        self.element.removeClass("number-error");
+                        o.validation = "valid";
+                        return "";
+                    }
+                } else {
+                    if (smallValue > bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.numberError;
+                    } else if (smallValue === bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.signalError;
+                    } else {
+                        self.element.removeClass("number-error");
+                        o.validation = "valid";
+                        return "";
+                    }
+                }
+            }
+
+        }
+    },
+
+    _setTitle: function (v) {
+        var self = this;
+        self.bigEditor.setTitle(v);
+        self.smallEditor.setTitle(v);
+        self.label.setTitle(v);
+    },
+
+    _setFocusEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self._setTitle("");
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                default :
+                    return
+            }
+
+        })
+    },
+    _setBlurEvent: function (w) {
+        var c = this.constants, self = this;
+        w.on(BI.SignEditor.EVENT_BLUR, function () {
+            BI.Bubbles.hide(c.typeError);
+            BI.Bubbles.hide(c.numberError);
+            BI.Bubbles.hide(c.signalError);
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data"));
+                    break;
+                case c.numberError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value"));
+                    break;
+                case c.signalError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value"));
+                    break;
+                default:
+                    self._setTitle("");
+            }
+        })
+    },
+
+    _setErrorEvent: function (w) {
+        var c = this.constants, self = this
+        w.on(BI.SignEditor.EVENT_ERROR, function () {
+            self._checkValidation();
+            BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                offsetStyle: "center"
+            });
+            self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+        })
+    },
+
+
+    _setValidEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_VALID, function () {
+            switch (self._checkValidation()) {
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                default:
+                    self.fireEvent(BI.NumericalInterval.EVENT_VALID);
+            }
+        })
+    },
+
+
+    _setEditorValueChangedEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_CHANGE, function () {
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                default :
+                    break;
+            }
+            self.fireEvent(BI.NumericalInterval.EVENT_CHANGE);
+        });
+    },
+
+    _setComboValueChangedEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.IconCombo.EVENT_CHANGE, function () {
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.numberError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.signalError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                default :
+                    self.fireEvent(BI.NumericalInterval.EVENT_CHANGE);
+                    self.fireEvent(BI.NumericalInterval.EVENT_VALID);
+            }
+        })
+    },
+
+
+    isValid: function () {
+        return this.options.validation === "valid";
+    },
+
+    setEnable: function (b) {
+        this.smallEditor.setEnable(b);
+        this.smallCombo.setEnable(b);
+        this.bigEditor.setEnable(b);
+        this.bigCombo.setEnable(b);
+    },
+
+    setMinEnable: function (b) {
+        this.smallEditor.setEnable(b);
+    },
+
+    setCloseMinEnable: function (b) {
+        this.smallCombo.setEnable(b);
+    },
+
+    setMaxEnable: function (b) {
+        this.bigEditor.setEnable(b);
+    },
+
+    setCloseMaxEnable: function (b) {
+        this.bigCombo.setEnable(b);
+    },
+
+    showNumTip: function () {
+        this.smallTip.setVisible(true);
+        this.bigTip.setVisible(true);
+    },
+
+    hideNumTip: function () {
+        this.smallTip.setVisible(false);
+        this.bigTip.setVisible(false);
+    },
+
+    setNumTip: function(numTip) {
+        this.smallTip.setText(numTip);
+        this.bigTip.setText(numTip);
+    },
+
+    getNumTip: function() {
+        return this.smallTip.getText();
+    },
+
+    setValue: function (data) {
+        data = data || {};
+        var self = this, combo_value;
+        if (BI.isNumeric(data.min) || BI.isEmptyString(data.min)) {
+            self.smallEditor.setValue(data.min);
+        }
+
+        if (!BI.isNotNull(data.min)) {
+            self.smallEditor.setValue("");
+        }
+
+        if (BI.isNumeric(data.max) || BI.isEmptyString(data.max)) {
+            self.bigEditor.setValue(data.max);
+        }
+
+        if (!BI.isNotNull(data.max)) {
+            self.bigEditor.setValue("");
+        }
+
+        if (!BI.isNull(data.closemin)) {
+            if (data.closemin === true) {
+                combo_value = 1
+            } else {
+                combo_value = 0
+            }
+            self.smallCombo.setValue(combo_value);
+        }
+
+        if (!BI.isNull(data.closemax)) {
+            if (data.closemax === true) {
+                combo_value = 1
+            } else {
+                combo_value = 0
+            }
+            self.bigCombo.setValue(combo_value);
+        }
+    },
+
+
+    getValue: function () {
+        var self = this, value = {}, minComboValue = self.smallCombo.getValue(), maxComboValue = self.bigCombo.getValue();
+        value.min = self.smallEditor.getValue();
+        value.max = self.bigEditor.getValue();
+        if (minComboValue[0] === 0) {
+            value.closemin = false
+        } else {
+            value.closemin = true
+        }
+
+        if (maxComboValue[0] === 0) {
+            value.closemax = false
+        } else {
+            value.closemax = true
+        }
+        return value;
+    }
+});
+BI.NumericalInterval.EVENT_CHANGE = "EVENT_CHANGE";
+BI.NumericalInterval.EVENT_VALID = "EVENT_VALID";
+BI.NumericalInterval.EVENT_ERROR = "EVENT_ERROR";
+$.shortcut("bi.numerical_interval", BI.NumericalInterval);/**
+ *
+ * 表格
+ *
+ * Created by GUY on 2015/9/22.
+ * @class BI.PageTableCell
+ * @extends BI.Single
+ */
+BI.PageTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.PageTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-page-table-cell",
+            text: "",
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.PageTableCell.superclass._init.apply(this, arguments);
+        var label = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            height: this.options.height,
+            text: this.options.text,
+            title: this.options.title,
+            value: this.options.value,
+            lgap: 5,
+            rgap: 5
+        });
+
+        if (BI.isNotNull(this.options.styles) && BI.isObject(this.options.styles)) {
+            this.element.css(this.options.styles);
+        }
+    }
+});
+
+$.shortcut("bi.page_table_cell", BI.PageTableCell);/**
+ * 分页表格
+ *
+ * Created by GUY on 2016/2/15.
+ * @class BI.PageTable
+ * @extends BI.Widget
+ */
+BI.PageTable = BI.inherit(BI.Widget, {
+
+    _const: {
+        scrollWidth: 18,
+        minScrollWidth: 100
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PageTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-page-table",
+            el: {
+                type: "bi.sequence_table"
+            },
+            pager: {
+                horizontal: {
+                    pages: false, //总页数
+                    curr: 1, //初始化当前页, pages为数字时可用
+
+                    hasPrev: BI.emptyFn,
+                    hasNext: BI.emptyFn,
+                    firstPage: 1,
+                    lastPage: BI.emptyFn
+                },
+                vertical: {
+                    pages: false, //总页数
+                    curr: 1, //初始化当前页, pages为数字时可用
+
+                    hasPrev: BI.emptyFn,
+                    hasNext: BI.emptyFn,
+                    firstPage: 1,
+                    lastPage: BI.emptyFn
+                }
+            },
+
+            itemsCreator: BI.emptyFn,
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: BI.emptyFn,
+
+            columnSize: [],
+            minColumnSize: [],
+            maxColumnSize: [],
+            headerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: [],
+
+            headerCellStyleGetter: BI.emptyFn,
+            summaryCellStyleGetter: BI.emptyFn,
+            sequenceCellStyleGetter: BI.emptyFn,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        });
+    },
+
+    _init: function () {
+        BI.PageTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.hCurr = 1;
+        this.vCurr = 1;
+
+        this.table = BI.createWidget(o.el, {
+            type: "bi.sequence_table",
+            width: o.width,
+            height: o.height - 30,
+
+            isNeedResize: true,
+            isResizeAdapt: false,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: o.columnSize,
+            minColumnSize: o.minColumnSize,
+            maxColumnSize: o.maxColumnSize,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter,
+
+            header: o.header,
+            items: o.items,
+            //交叉表头
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems
+        });
+
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+
+        this.pager = BI.createWidget(o.pager, {
+            type: "bi.direction_pager",
+            height: 30
+        });
+        this.pager.on(BI.Pager.EVENT_CHANGE, function () {
+            var vpage = this.getVPage && this.getVPage();
+            if (BI.isNull(vpage)) {
+                vpage = this.getCurrentPage();
+            }
+            var hpage = this.getHPage && this.getHPage();
+            o.itemsCreator({
+                vpage: vpage,
+                hpage: hpage
+            }, function (items, header, crossItems, crossHeader) {
+                self.table.setVPage ? self.table.setVPage(vpage) : self.table.setCurrentPage(vpage);
+                self.table.setHPage && self.table.setHPage(hpage);
+                self.populate.apply(self, arguments);
+            });
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.table,
+                left: 0,
+                top: 0
+            }, {
+                el: this.pager,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    setHPage: function (v) {
+        this.hCurr = v;
+        this.pager.setHPage && this.pager.setHPage(v);
+        this.table.setHPage && this.table.setHPage(v);
+    },
+
+    setVPage: function (v) {
+        this.vCurr = v;
+        this.pager.setVPage && this.pager.setVPage(v);
+        this.table.setVPage && this.table.setVPage(v);
+    },
+
+    getHPage: function () {
+        var hpage = this.pager.getHPage && this.pager.getHPage();
+        if (BI.isNotNull(hpage)) {
+            return hpage;
+        }
+        hpage = this.pager.getCurrentPage && this.pager.getCurrentPage();
+        if (BI.isNotNull(hpage)) {
+            return hpage;
+        }
+        return this.hpage;
+    },
+
+    getVPage: function () {
+        var vpage = this.pager.getVPage && this.pager.getVPage();
+        if (BI.isNotNull(vpage)) {
+            return vpage;
+        }
+        vpage = this.pager.getCurrentPage && this.pager.getCurrentPage();
+        if (BI.isNotNull(vpage)) {
+            return vpage;
+        }
+        return this.vpage;
+    },
+
+    setWidth: function (width) {
+        BI.PageTable.superclass.setWidth.apply(this, arguments);
+        this.table.setWidth(width);
+    },
+
+    setHeight: function (height) {
+        BI.PageTable.superclass.setHeight.apply(this, arguments);
+        this.table.setHeight(height - 30);
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    restore: function () {
+        this.table.restore();
+    },
+
+    attr: function () {
+        BI.PageTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    populate: function () {
+        this.pager.populate();
+        this.table.populate.apply(this.table, arguments);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        this.pager && this.pager.destroy();
+        BI.PageTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.page_table', BI.PageTable);/**
+ * @class BI.DateParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.DateParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DateParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.date_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.DateParamCombo.hideView();
+        });
+
+        this.DateParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.DateParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.DateParamCombo.EVENT_CONFIRM);
+        });
+
+        this.DateParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+        BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Quarter_De");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_De");
+            case BICst.YEAR_WEEK:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Week_De");
+            case BICst.YEAR_DAY:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Day_De");
+            case BICst.MONTH_WEEK:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Week_De");
+            case BICst.MONTH_DAY:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Day_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.DateParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.DateParamCombo.superclass.setEnable.apply(this, arguments);
+        this.DateParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.DateParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.DateParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.date_param_combo", BI.DateParamCombo);/**
+ * 普通控件
+ *
+ * @class BI.DateParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.DateParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-date-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.DateParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param3_date_item",
+            value: BICst.YEAR,
+            selected: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_QUARTER,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_MONTH,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_DAY,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.MONTH_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.MONTH_DAY,
+            disabled: true
+        }]
+    }
+});
+BI.DateParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.date_param_popup_view', BI.DateParamPopupView);/**
+ * @class BI.DateIntervalParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.DateIntervalParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateIntervalParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-interval-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DateIntervalParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.date_interval_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.DateIntervalParamCombo.hideView();
+        });
+
+        this.DateIntervalParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.DateIntervalParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.DateIntervalParamCombo.EVENT_CONFIRM);
+        });
+
+        this.DateIntervalParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Basic_Quarter");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_Fen");
+            case BICst.YEAR_WEEK:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Week");
+            case BICst.YEAR_DAY:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Day_De");
+            case BICst.MONTH_WEEK:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Week");
+            case BICst.MONTH_DAY:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Day_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.DateIntervalParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.DateIntervalParamCombo.superclass.setEnable.apply(this, arguments);
+        this.DateIntervalParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.DateIntervalParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.DateIntervalParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.date_interval_param_combo", BI.DateIntervalParamCombo);/**
+ * 普通控件
+ *
+ * @class BI.DateIntervalParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.DateIntervalParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateIntervalParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-date-interval-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.DateIntervalParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            value: BICst.YEAR,
+            selected: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_QUARTER,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_MONTH,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_DAY,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.MONTH_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.MONTH_DAY,
+            disabled: true
+        }]
+    }
+});
+BI.DateIntervalParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.date_interval_param_popup_view', BI.DateIntervalParamPopupView);/**
+ * 普通控件
+ *
+ * @class BI.Param0DateItem
+ * @extends BI.Single
+ */
+BI.Param0DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param0DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param0-date-item',
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param0DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year_Fen"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getInputValue: function () {
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return BICst.YEAR;
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+    }
+});
+
+BI.Param0DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.param0_date_item', BI.Param0DateItem);/**
+ * 普通控件
+ *
+ * @class BI.Param1DateItem
+ * @extends BI.Single
+ */
+BI.Param1DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param1DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param1-date-item',
+            value: BI.Param1DateItem.YEAR_DAY,
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param1DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.secondEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.secondEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.secondCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.firstCombo.setValue(0);
+        this.secondCombo.setValue(0);
+        var textJson = this._getTextByDateType();
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: textJson.ftext,
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                el: this.secondCombo,
+                rgap: 5
+            }, this.secondEditor, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: textJson.stext,
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _getTextByDateType: function(){
+        switch (this.options.value) {
+            case BI.Param1DateItem.MONTH_WEEK:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Week_De")};
+            case BI.Param1DateItem.MONTH_DAY:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param1DateItem.YEAR_MONTH:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Month_De")};
+            case BI.Param1DateItem.YEAR_DAY:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param1DateItem.YEAR_QUARTER:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Quarter_De")};
+            case BI.Param1DateItem.YEAR_WEEK:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Week_De")};
+        }
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        v.svalue = v.svalue || o.defaultEditorValue;
+        v.soffset = v.soffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    getInputValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0],
+            svalue: this.secondEditor.getValue() || 0,
+            soffset: this.secondCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+        this.secondEditor.setValue(v.svalue);
+        this.secondCombo.setValue([v.soffset]);
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.secondEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+        this.secondCombo.setEnable(!!b);
+    }
+});
+
+BI.Param1DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+BI.extend(BI.Param1DateItem , {
+    YEAR_QUARTER: BICst.YEAR_QUARTER,
+    YEAR_MONTH: BICst.YEAR_MONTH,
+    YEAR_WEEK: BICst.YEAR_WEEK,
+    YEAR_DAY: BICst.YEAR_DAY,
+    MONTH_WEEK: BICst.MONTH_WEEK,
+    MONTH_DAY: BICst.MONTH_DAY
+});
+$.shortcut('bi.param1_date_item', BI.Param1DateItem);/**
+ * 普通控件
+ *
+ * @class BI.Param2DateItem
+ * @extends BI.Single
+ */
+BI.Param2DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param2DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param2-date-item',
+            value: BI.Param2DateItem.YEAR_DAY,
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param2DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.secondEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.secondEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.secondCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.firstCombo.setValue(0);
+        this.secondCombo.setValue(0);
+        var textJson = this._getTextByDateType();
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: textJson.ftext,
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                el: this.secondCombo,
+                rgap: 5
+            }, this.secondEditor, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: textJson.stext,
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _getTextByDateType: function(){
+        switch (this.options.value) {
+            case BI.Param2DateItem.MONTH_WEEK:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Week_Of_Week")};
+            case BI.Param2DateItem.MONTH_DAY:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param2DateItem.YEAR_MONTH:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Month_De_Month")};
+            case BI.Param2DateItem.YEAR_DAY:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param2DateItem.YEAR_QUARTER:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Quarter_Of_Quarter")};
+            case BI.Param2DateItem.YEAR_WEEK:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Week_Of_Week")};
+        }
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        v.svalue = v.svalue || o.defaultEditorValue;
+        v.soffset = v.soffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    getInputValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0],
+            svalue: this.secondEditor.getValue() || 0,
+            soffset: this.secondCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+        this.secondEditor.setValue(v.svalue);
+        this.secondCombo.setValue([v.soffset]);
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.secondEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+        this.secondCombo.setEnable(!!b);
+    }
+});
+
+BI.Param2DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+BI.extend(BI.Param2DateItem , {
+    YEAR_QUARTER: BICst.YEAR_QUARTER,
+    YEAR_MONTH: BICst.YEAR_MONTH,
+    YEAR_WEEK: BICst.YEAR_WEEK,
+    YEAR_DAY: BICst.YEAR_DAY,
+    MONTH_WEEK: BICst.MONTH_WEEK,
+    MONTH_DAY: BICst.MONTH_DAY
+});
+$.shortcut('bi.param2_date_item', BI.Param2DateItem);/**
+ * 普通控件
+ *
+ * @class BI.Param3DateItem
+ * @extends BI.Single
+ */
+BI.Param3DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param3DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param3-date-item',
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param3DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Multi_Date_Year_Begin"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getInputValue: function () {
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return BICst.YEAR;
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+    }
+});
+
+BI.Param3DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.param3_date_item', BI.Param3DateItem);/**
+ * @class BI.RangeValueCombo
+ * @extend BI.Widget
+ */
+BI.RangeValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.RangeValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-range-value-combo",
+            width: 100,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.RangeValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.dateRangeCombo = BI.createWidget({
+            type: "bi.text_value_combo",
+            height: o.height,
+            width: o.width,
+            items: BICst.Date_Range_FILTER_COMBO
+        });
+        this.dateRangeCombo.on(BI.TextValueCombo.EVENT_CHANGE, function(){
+            self.fireEvent(BI.RangeValueCombo.EVENT_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.default",
+            element: this,
+            items: [this.dateRangeCombo]
+        });
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.dateRangeCombo.setValue(v.type);
+    },
+
+    getValue: function () {
+        return {
+            type: this.dateRangeCombo.getValue()[0]
+        };
+    }
+});
+BI.RangeValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.range_value_combo", BI.RangeValueCombo);/**
+ * @class BI.YearParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+
+        this.popup = BI.createWidget({
+            type: 'bi.multi_popup_view',
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.None,
+                items: [{
+                    type: "bi.year_param_item"
+                }],
+                layouts: [{
+                    type: "bi.vertical",
+                    vgap: 5,
+                    hgap: 5
+                }]
+            },
+            minWidth: 310,
+            maxHeight: 300,
+            stopPropagation: false
+        });
+
+        this.popup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function () {
+            self.YearParamCombo.hideView();
+        });
+
+        this.YearParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        return v.fvalue + BI.i18nText("BI-Year") +
+            (v.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+    },
+
+    getCalculationValue: function () {
+        var value = this.YearParamCombo.getValue()[0];
+        var fPrevOrAfter = value.foffset === 0 ? -1 : 1;
+        var start = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), 0, 1);
+        var end = new Date(start.getFullYear(), 11, 31);
+        return {
+            start: start,
+            end: end
+        };
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.YearParamCombo.setValue(v.value);
+        this.trigger.setValue(this._getShowTextByValue(v.value));
+    },
+
+    getValue: function () {
+        return {
+            type: BICst.YEAR,
+            value: this.YearParamCombo.getValue()[0]
+        }
+    }
+
+});
+BI.YearParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_param_combo", BI.YearParamCombo);/**
+ * 普通控件
+ *
+ * @class BI.YearParamItem
+ * @extends BI.Single
+ */
+BI.YearParamItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearParamItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-param-item',
+            width: 310,
+            height: 20,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.YearParamItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year_Fen"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        if(BI.isArray(v)){
+            v = v[0];
+        }
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    }
+});
+
+BI.YearParamItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_param_item', BI.YearParamItem);/**
+ * @class BI.YearMonthParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearMonthParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-month-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearMonthParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.year_month_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.YearMonthParamCombo.hideView();
+        });
+
+        this.YearMonthParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearMonthParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearMonthParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearMonthParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.YearMonthParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.YearMonthParamCombo.superclass.setEnable.apply(this, arguments);
+        this.YearMonthParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.YearMonthParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.YearMonthParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_month_param_combo", BI.YearMonthParamCombo);/**
+ * 普通控件
+ *
+ * @class BI.YearMonthParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.YearMonthParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-month-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.YearMonthParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            selected: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_MONTH,
+            disabled: true
+        }]
+    }
+});
+BI.YearMonthParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_month_param_popup_view', BI.YearMonthParamPopupView);/**
+ * @class BI.YearSeasonParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearSeasonParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearSeasonParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-season-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearSeasonParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.year_season_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.YearSeasonParamCombo.hideView();
+        });
+
+        this.YearSeasonParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearSeasonParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearSeasonParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearSeasonParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Quarter_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.YearSeasonParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.YearSeasonParamCombo.superclass.setEnable.apply(this, arguments);
+        this.YearSeasonParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.YearSeasonParamCombo.getValue();
+        //return BI.extend(this.popup.getCalculationValue(), this.YearSeasonParamCombo.getValue());
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.YearSeasonParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_season_param_combo", BI.YearSeasonParamCombo);/**
+ * 普通控件
+ *
+ * @class BI.YearSeasonParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.YearSeasonParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearSeasonParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-season-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.YearSeasonParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            selected: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_QUARTER,
+            disabled: true
+        }]
+    }
+});
+BI.YearSeasonParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_season_param_popup_view', BI.YearSeasonParamPopupView);/**
+ * 路径选择
+ *
+ * Created by GUY on 2015/12/4.
+ * @class BI.PathChooser
+ * @extends BI.Widget
+ */
+BI.PathChooser = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#c4c6c6",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PathChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-path-chooser",
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.PathChooser.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _createRegions: function (regions) {
+        var self = this;
+        this.regions = BI.createWidgets(BI.map(regions, function (i, region) {
+            return {
+                type: "bi.path_region",
+                title: self.texts[region] || region
+            }
+        }));
+        this.regionMap = {};
+        BI.each(regions, function (i, region) {
+            self.regionMap[region] = i;
+        });
+        this.container = BI.createWidget({
+            type: "bi.horizontal",
+            verticalAlign: "top",
+            scrollx: false,
+            scrolly: false,
+            hgap: 10,
+            items: this.regions
+        });
+        BI.createWidget({
+            type: "bi.vertical_adapt",
+            element: this,
+            scrollable: true,
+            hgap: 10,
+            items: [this.container]
+        });
+    },
+
+    getRegionIndexById: function (id) {
+        var node = this.store[id];
+        var regionType = node.get("region");
+        return this.regionMap[regionType];
+    },
+
+    _drawPath: function (start, offset, index) {
+        var self = this;
+        var starts = [];
+        if (this.start.contains(start)) {
+            starts = this.start;
+        } else {
+            starts = [start];
+        }
+
+        BI.each(starts, function (i, s) {
+            BI.each(self.radios[s], function (i, rad) {
+                rad.setSelected(false);
+            });
+            BI.each(self.lines[s], function (i, line) {
+                line.attr("stroke", self._const.lineColor);
+            });
+            BI.each(self.regionIndexes[s], function (i, idx) {
+                self.regions[idx].reset();
+            });
+        });
+
+        BI.each(this.routes[start][index], function (i, id) {
+            var regionIndex = self.getRegionIndexById(id);
+            self.regions[regionIndex].setSelect(offset + index, id);
+        });
+        var current = BI.last(this.routes[start][index]);
+
+        while (current && this.routes[current] && this.routes[current].length === 1) {
+            BI.each(this.routes[current][0], function (i, id) {
+                var regionIndex = self.getRegionIndexById(id);
+                self.regions[regionIndex].setSelect(0, id);
+            });
+            this.lines[current][0].attr("stroke", self._const.selectLineColor).toFront();
+            current = BI.last(this.routes[current][0]);
+        }
+        this.lines[start][index].attr("stroke", self._const.selectLineColor).toFront();
+        this.radios[start] && this.radios[start][index] && this.radios[start][index].setSelected(true);
+    },
+
+    _drawRadio: function (start, offset, index, x, y) {
+        var self = this;
+        var radio = BI.createWidget({
+            type: "bi.radio",
+            cls: "path-chooser-radio",
+            selected: offset + index === 0,
+            start: start,
+            index: index
+        });
+        radio.on(BI.Radio.EVENT_CHANGE, function () {
+            self._drawPath(start, offset, index);
+            self.fireEvent(BI.PathChooser.EVENT_CHANGE, start, index);
+        });
+        if (!this.radios[start]) {
+            this.radios[start] = [];
+        }
+        this.radios[start].push(radio);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [{
+                el: radio,
+                left: x - 6.5,
+                top: y - 6.5
+            }]
+        })
+    },
+
+    _drawLine: function (start, lines) {
+        var self = this;
+        if (!this.lines[start]) {
+            this.lines[start] = [];
+        }
+        if (!this.pathes[start]) {
+            this.pathes[start] = [];
+        }
+        var startRegionIndex = this.getRegionIndexById(start);
+        //start所在的位置,然后接着往下画其他的路径
+        var offset = this.regions[startRegionIndex].getIndexByValue(start);
+        BI.each(lines, function (i, line) {
+            self.pathes[start][i] = [];
+            var idx = i + offset;
+            var path = "";
+            var stop = 47.5 + 29 * idx;
+            var sleft = 50 + 100 * startRegionIndex;
+            var radioStartX = sleft, radioStartY = stop;
+            var etop = stop;
+            var endRegionIndex = self.getRegionIndexById(BI.last(line));
+            var endOffset = self.regions[endRegionIndex].getIndexByValue(BI.last(line));
+            var eleft = 50 + 100 * endRegionIndex;
+            if (self.start.contains(start)) {
+                radioStartX = sleft - 50;
+                path += "M" + (sleft - 50) + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft - 50,
+                    y: stop
+                })
+            } else if (idx === 0) {
+                radioStartX = sleft + 50;
+                path += "M" + sleft + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft,
+                    y: stop
+                })
+            } else {
+                radioStartX = sleft + 50;
+                path += "M" + sleft + "," + 47.5 + "L" + (sleft + 50) + "," + 47.5 + "L" + (sleft + 50) + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft,
+                    y: 47.5
+                });
+                self.pathes[start][i].push({
+                    x: sleft + 50,
+                    y: 47.5
+                });
+                self.pathes[start][i].push({
+                    x: sleft + 50,
+                    y: stop
+                });
+            }
+            if (idx > 0) {
+                var endY = endOffset * 29 + 47.5;
+                path += "L" + (eleft - 50) + "," + etop + "L" + (eleft - 50) + "," + endY + "L" + eleft + "," + endY;
+                self.pathes[start][i].push({
+                    x: eleft - 50,
+                    y: etop
+                });
+                self.pathes[start][i].push({
+                    x: eleft - 50,
+                    y: endY
+                });
+                self.pathes[start][i].push({
+                    x: eleft,
+                    y: endY
+                });
+            } else {
+                path += "L" + eleft + "," + etop;
+                self.pathes[start][i].push({
+                    x: eleft,
+                    y: etop
+                });
+            }
+
+            var graph = self.svg.path(path)
+                .attr({
+                    stroke: idx === 0 ? self._const.selectLineColor : self._const.lineColor,
+                    'stroke-dasharray': '-'
+                });
+            self.lines[start].push(graph);
+            if (lines.length > 1) {
+                self.lines[start][0].toFront();
+            }
+            //第一个元素无论有多少个都要显示radio
+            if (self.start.contains(start)) {
+                self.lines[self.regions[0].getValueByIndex(0)][0].toFront();
+            }
+            if (lines.length > 1 || self.start.contains(start)) {
+                self._drawRadio(start, offset, i, radioStartX, radioStartY);
+            }
+        });
+    },
+
+    _drawLines: function (routes) {
+        var self = this;
+        this.lines = {};
+        this.pathes = {};
+        this.radios = {};
+        this.regionIndexes = {};
+        BI.each(routes, function (k, route) {
+            if (!self.regionIndexes[k]) {
+                self.regionIndexes[k] = [];
+            }
+            BI.each(route, function (i, rs) {
+                BI.each(rs, function (j, id) {
+                    var regionIndex = self.getRegionIndexById(id);
+                    if (!BI.contains(self.regionIndexes[k], regionIndex)) {
+                        self.regionIndexes[k].push(regionIndex);
+                    }
+                });
+            })
+        });
+        BI.each(routes, function (k, route) {
+            self._drawLine(k, route);
+        });
+    },
+
+    _pushNodes: function (nodes) {
+        var self = this;
+        var indexes = [];
+        for (var i = 0; i < nodes.length; i++) {
+            var id = nodes[i];
+            var index = self.getRegionIndexById(id);
+            indexes.push(index);
+            var region = self.regions[index];
+            if (i === nodes.length - 1) {
+                if (!region.hasItem(id)) {
+                    region.addItem(id, self.texts[id]);
+                }
+                break;
+            }
+            if (i > 0 || self.start.contains(id)) {
+                region.addItem(id, self.texts[id]);
+            }
+        }
+        for (var i = BI.first(indexes); i < BI.last(indexes); i++) {
+            if (!BI.contains(indexes, i)) {
+                self.regions[i].addItem("");
+            }
+        }
+    },
+
+    _createNodes: function () {
+        var self = this, o = this.options;
+        this.store = {};
+        this.texts = {};
+        this.start = [];
+        this.end = [];
+        BI.each(o.items, function (i, item) {
+            self.start.push(BI.first(item).value);
+            self.end.push(BI.last(item).value);
+        });
+        this.start = BI.uniq(this.start);
+        this.end = BI.uniq(this.end);
+        var regions = [];
+        var tree = new BI.Tree();
+        var branches = {}, max = 0;
+        BI.each(o.items, function (i, items) {
+            BI.each(items, function (j, item) {
+                if (!BI.has(branches, item.value)) {
+                    branches[item.value] = 0;
+                }
+                branches[item.value]++;
+                max = Math.max(max, branches[item.value]);
+                var prev = {};
+                if (j > 0) {
+                    prev = items[j - 1];
+                }
+                var parent = self.store[prev.value || ""];
+                var node = self.store[item.value] || new BI.Node(item.value);
+                node.set(item);
+                self.store[item.value] = node;
+                self.texts[item.value] = item.text;
+                self.texts[item.region] = item.regionText;
+                parent = BI.isNull(parent) ? tree.getRoot() : parent;
+                if (parent.getChildIndex(item.value) === -1) {
+                    tree.addNode(parent, node);
+                }
+            })
+        });
+
+        //算出区域列表
+        tree.traverse(function (node) {
+            BI.each(node.getChildren(), function (i, child) {
+                if (BI.contains(regions, child.get("region"))) {
+                    var index1 = BI.indexOf(regions, node.get("region"));
+                    var index2 = BI.indexOf(regions, child.get("region"));
+                    //交换区域
+                    if (index1 > index2) {
+                        var t = regions[index2];
+                        for(var j =index2; j < index1; j++){
+                            regions[j] = regions[j+1];
+                        }
+                        regions[index1] = t;
+                    }
+                } else {
+                    regions.push(child.get("region"));
+                }
+            });
+        });
+        this._createRegions(regions);
+
+        //算出节点
+        BI.each(branches, function (k, branch) {
+            if (branch < max) {
+                delete branches[k];
+            }
+        });
+
+        //过滤节点
+        var nodes = [];
+        var n = tree.getRoot();
+        while (n && n.getChildrenLength() === 1) {
+            if (BI.has(branches, n.getChildren()[0].id)) {
+                delete branches[n.getChildren()[0].id];
+                n = n.getChildren()[0];
+            } else {
+                n = null;
+            }
+        }
+        tree.traverse(function (node) {
+            if (BI.has(branches, node.id)) {
+                nodes.push(node.id);
+                delete branches[node.id];
+            }
+        });
+
+        //填充节点
+        var routes = {};
+        var s, e;
+        for (var i = 0, len = nodes.length; i < len + 1; i++) {
+            if (len === 0) {
+                s = [];
+                BI.each(this.start, function (i, id) {
+                    s.push(tree.search(id));
+                });
+                e = [];
+                BI.each(this.end, function (i, id) {
+                    e.push(tree.search(id));
+                });
+            } else if (i === len) {
+                s = e;
+                e = [];
+                BI.each(this.end, function (i, id) {
+                    e.push(tree.search(id));
+                });
+            } else if (i === 0) {
+                s = [];
+                BI.each(this.start, function (i, id) {
+                    s.push(tree.search(id));
+                });
+                e = [tree.search(nodes[i])];
+            } else {
+                s = [tree.search(e[0] || tree.getRoot(), nodes[i - 1])];
+                e = [tree.search(s[0], nodes[i])];
+            }
+            BI.each(s, function (i, n) {
+                tree._recursion(n, [n.id], function (node, route) {
+                    if (e.contains(node)) {
+                        if (!routes[n.id]) {
+                            routes[n.id] = [];
+                        }
+                        routes[n.id].push(route);
+                        self._pushNodes(route);
+                        if (e.length <= 1) {
+                            return true;
+                        }
+                    }
+                })
+            });
+        }
+        this.routes = routes;
+        this._drawLines(routes);
+    },
+
+    _unselectAllPath: function () {
+        var self = this;
+        BI.each(this.radios, function (idx, rad) {
+            BI.each(rad, function (i, r) {
+                r.setSelected(false);
+            });
+        });
+        BI.each(this.lines, function (idx, line) {
+            BI.each(line, function (i, li) {
+                li.attr("stroke", self._const.lineColor);
+            });
+        });
+        BI.each(this.regions, function (idx, region) {
+            region.reset();
+        });
+    },
+
+    populate: function (items) {
+        this.options.items = items || [];
+        var self = this;
+        this.empty();
+        if (this.options.items.length <= 0) {
+            return;
+        }
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+        this._createNodes();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [{
+                el: this.svg,
+                top: 0,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        this._unselectAllPath();
+        var nodes = BI.keys(this.routes), self = this;
+        var result = [], array = [];
+        BI.each(v, function (i, val) {
+            if (BI.contains(nodes, val)) {
+                if (array.length > 0) {
+                    array.push(val);
+                    result.push(array);
+                    array = [];
+                }
+            }
+            array.push(val);
+        });
+        if (array.length > 0) {
+            result.push(array);
+        }
+        //画这n条路径
+        BI.each(result, function (idx, path) {
+            var start = path[0];
+            var index = BI.findIndex(self.routes[start], function (idx, p) {
+                if (BI.isEqual(path, p)) {
+                    return true;
+                }
+            });
+            if (index >= 0) {
+                var startRegionIndex = self.getRegionIndexById(start);
+                var offset = self.regions[startRegionIndex].getIndexByValue(start);
+                self._drawPath(start, offset, index);
+            }
+        });
+    },
+
+    getValue: function () {
+        var path = [];
+        BI.each(this.regions, function (i, region) {
+            var val = region.getValue();
+            if (BI.isKey(val)) {
+                path.push(val);
+            }
+        });
+        return path;
+    }
+});
+BI.PathChooser.EVENT_CHANGE = "PathChooser.EVENT_CHANGE";
+$.shortcut("bi.path_chooser", BI.PathChooser);/**
+ * 路径选择区域
+ *
+ * Created by GUY on 2015/12/4.
+ * @class BI.PathRegion
+ * @extends BI.Widget
+ */
+BI.PathRegion = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PathRegion.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-path-region",
+            width: 80,
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.PathRegion.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.zIndex = 100;
+        var title = BI.createWidget({
+            type: "bi.label",
+            text: o.title,
+            title: o.title,
+            height: 30
+        });
+        title.element.css("zIndex", this.zIndex--);
+        this.items = [];
+        this.vertical = BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            bgap: 5,
+            hgap: 10,
+            items: [title]
+        })
+    },
+
+    hasItem: function (val) {
+        return BI.any(this.items, function (i, item) {
+            return val === item.getValue();
+        });
+    },
+
+    addItem: function (value, text) {
+        if (BI.isKey(value)) {
+            var label = BI.createWidget({
+                type: "bi.label",
+                cls: "path-region-label",
+                text: text,
+                value: value,
+                title: text || value,
+                height: 22
+            });
+        } else {
+            var label = BI.createWidget({
+                type: "bi.layout",
+                height: 24
+            });
+        }
+        label.element.css("zIndex", this.zIndex--);
+        this.items.push(label);
+        this.vertical.addItem(label);
+        if (this.items.length === 1) {
+            this.setSelect(0, value);
+        }
+    },
+
+    reset: function () {
+        BI.each(this.items, function (i, item) {
+            item.element.removeClass("active");
+        });
+    },
+
+    setSelect: function (index, value) {
+        this.reset();
+        if (this.items.length <= 0) {
+            return;
+        }
+        if (this.items.length === 1) {
+            this.items[0].element.addClass("active");
+            return;
+        }
+        if (this.items[index].attr("value") === value) {
+            this.items[index].element.addClass("active");
+        }
+    },
+
+    setValue: function (value) {
+        this.setSelect(this.getIndexByValue(value), value);
+    },
+
+    getValueByIndex: function (idx) {
+        return this.items[idx].attr("value");
+    },
+
+    getIndexByValue: function (value) {
+        return BI.findIndex(this.items, function (i, item) {
+            return item.attr("value") === value;
+        });
+    },
+
+    getValue: function () {
+        var res;
+        BI.any(this.items, function (i, item) {
+            if (item.element.hasClass("active")) {
+                res = item.getValue();
+                return true;
+            }
+        });
+        return res;
+    }
+});
+BI.PathRegion.EVENT_CHANGE = "PathRegion.EVENT_CHANGE";
+$.shortcut("bi.path_region", BI.PathRegion);/**
+ * 预览表列
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTableCell
+ * @extends BI.Widget
+ */
+BI.PreviewTableCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTableCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.preview_table_cell', BI.PreviewTableCell);/**
+ * 预览表
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTableHeaderCell
+ * @extends BI.Widget
+ */
+BI.PreviewTableHeaderCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTableHeaderCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table-header-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTableHeaderCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.preview_table_header_cell', BI.PreviewTableHeaderCell);/**
+ * 预览表
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTable
+ * @extends BI.Widget
+ */
+BI.PreviewTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table",
+            isNeedFreeze: false,
+            freezeCols: [],
+            rowSize: null,
+            columnSize: [],
+            headerRowSize: 30,
+            header: [],
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            element: this,
+            isNeedResize: false,
+
+            isResizeAdapt: false,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            rowSize: o.rowSize,
+            columnSize: o.columnSize,
+            headerRowSize: o.headerRowSize,
+
+            header: BI.map(o.header, function (i, items) {
+                return BI.map(items, function (j, item) {
+                    return BI.extend({
+                        type: "bi.preview_table_header_cell"
+                    }, item);
+                });
+            }),
+            items: BI.map(o.items, function (i, items) {
+                return BI.map(items, function (j, item) {
+                    return BI.extend({
+                        type: "bi.preview_table_cell"
+                    }, item);
+                });
+            })
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            self._adjustColumns();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            self._adjustColumns();
+        });
+    },
+
+    //是否有自适应调节的列,即列宽为""
+    _hasAdaptCol: function (columnSize) {
+        return BI.any(columnSize, function (i, size) {
+            return size === "";
+        })
+    },
+
+    _isPercentage: function (columnSize) {
+        return columnSize[0] <= 1;
+    },
+
+    _adjustColumns: function () {
+        var self = this, o = this.options;
+        if (o.isNeedFreeze === true) {
+            //如果存在百分比的情况
+            if (this._isPercentage(o.columnSize)) {
+                if (this._hasAdaptCol(o.columnSize)) {
+                    var findCols = [], remain = 0;
+                    BI.each(o.columnSize, function (i, size) {
+                        if (size === "") {
+                            findCols.push(i);
+                        } else {
+                            remain += size;
+                        }
+                    });
+                    remain = 1 - remain;
+                    var average = remain / findCols.length;
+                    BI.each(findCols, function (i, col) {
+                        o.columnSize[col] = average;
+                    });
+                }
+                var isRight = BI.first(o.freezeCols) !== 0;
+                var freezeSize = [], notFreezeSize = [];
+                BI.each(o.columnSize, function (i, size) {
+                    if (o.freezeCols.contains(i)) {
+                        freezeSize.push(size);
+                    } else {
+                        notFreezeSize.push(size);
+                    }
+                });
+                var sumFreezeSize = BI.sum(freezeSize), sumNotFreezeSize = BI.sum(notFreezeSize);
+                BI.each(freezeSize, function (i, size) {
+                    freezeSize[i] = size / sumFreezeSize;
+                });
+                BI.each(notFreezeSize, function (i, size) {
+                    notFreezeSize[i] = size / sumNotFreezeSize;
+                });
+                this.table.setRegionColumnSize(isRight ? ["fill", sumFreezeSize] : [sumFreezeSize, "fill"]);
+                this.table.setColumnSize(isRight ? (notFreezeSize.concat(freezeSize)) : (freezeSize.concat(notFreezeSize)));
+            }
+        } else {
+            //如果存在自适应宽度的列或者是百分比计算的列,需要将整个表宽设为100%
+            if (this._hasAdaptCol(o.columnSize) || this._isPercentage(o.columnSize)) {
+                this.table.setRegionColumnSize(["100%"]);
+            }
+        }
+    },
+
+    setColumnSize: function (columnSize) {
+        return this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    getCalculateColumnSize: function () {
+        return this.table.getCalculateColumnSize();
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        return this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        return this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize()
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize()
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        return this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        return this.table.setLeftHorizontalScroll(scrollLeft)
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        return this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    populate: function (items, header) {
+        this.table.populate(items, header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.PreviewTable.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE";
+$.shortcut('bi.preview_table', BI.PreviewTable);/**
+ * 季度下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.QuarterCombo
+ * @extends BI.Widget
+ */
+BI.QuarterCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-quarter-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.QuarterCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.storeValue = "";
+        this.trigger = BI.createWidget({
+            type: "bi.quarter_trigger"
+        });
+
+        this.trigger.on(BI.QuarterTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_CHANGE, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_START, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_STOP, function(){
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_CONFIRM, function () {
+            if(self.combo.isViewVisible()) {
+                return;
+            }
+            if(this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getKey());
+            }else if(!this.getKey()){
+                self.setValue();
+            }
+            self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM);
+        });
+        this.popup = BI.createWidget({
+            type: "bi.quarter_popup"
+        });
+
+        this.popup.on(BI.QuarterPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                el: this.popup
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue() || "";
+    }
+});
+
+BI.QuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.quarter_combo', BI.QuarterCombo);/**
+ * 季度展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.QuarterPopup
+ * @extends BI.Trigger
+ */
+BI.QuarterPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-quarter-popup"
+        });
+    },
+
+    _init: function () {
+        BI.QuarterPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        var items = [{
+            text: Date._QN[01],
+            value: 1
+        }, {
+            text: Date._QN[2],
+            value: 2
+        }, {
+            text: Date._QN[3],
+            value: 3
+        }, {
+            text: Date._QN[4],
+            value: 4
+        }];
+        items = BI.map(items, function (j, item) {
+            return BI.extend(item, {
+                type: "bi.text_item",
+                cls: "bi-list-item-active",
+                textAlign: "left",
+                whiteSpace: "nowrap",
+                once: false,
+                forceSelected: true,
+                height: 25
+            });
+        });
+
+        this.quarter = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(items, {}),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.quarter.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MonthPopup.EVENT_CHANGE);
+            }
+        })
+    },
+
+    getValue: function () {
+        return this.quarter.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.quarter.setValue([v]);
+    }
+});
+BI.QuarterPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.quarter_popup", BI.QuarterPopup);/**
+ * 季度trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.QuarterTrigger
+ * @extends BI.Trigger
+ */
+BI.QuarterTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 30,
+        textWidth: 40,
+        errorText: BI.i18nText("BI-Quarter_Trigger_Error_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-quarter-trigger",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.QuarterTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 4);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.QuarterTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_STOP);
+        });
+
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        baseCls: "bi-trigger-quarter-text",
+                        text: BI.i18nText("BI-Multi_Date_Quarter"),
+                        width: c.textWidth
+                    },
+                    width: c.textWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+
+    setValue: function (v) {
+        this.editor.setState(v);
+        this.editor.setValue(v);
+        this.editor.setTitle(v);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    }
+});
+BI.QuarterTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.QuarterTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.QuarterTrigger.EVENT_START = "EVENT_START";
+BI.QuarterTrigger.EVENT_STOP = "EVENT_STOP";
+BI.QuarterTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.quarter_trigger", BI.QuarterTrigger);/**
+ * 关联视图字段Item
+ *
+ * Created by GUY on 2015/12/23.
+ * @class BI.RelationViewItem
+ * @extends BI.Widget
+ */
+BI.RelationViewItem = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-item",
+            height: 25,
+            hoverIn: BI.emptyFn,
+            hoverOut: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.element.hover(o.hoverIn, o.hoverOut);
+        var items = [];
+        if (o.isPrimary) {
+            items.push({
+                type: "bi.icon",
+                width: 16,
+                height: 16,
+                title: BI.i18nText("BI-Primary_Key")
+            });
+        }
+        items.push({
+            type: "bi.label",
+            text: o.text,
+            value: o.value,
+            height: o.height,
+            textAlign: "left",
+            width: o.isPrimary ? 70 : 90
+        });
+        BI.createWidget({
+            type: "bi.vertical_adapt",
+            element: this,
+            items: items,
+            cls: "primary-key-font",
+            lgap: 5
+        });
+    },
+
+    enableHover: function (opt) {
+        BI.RelationViewRegion.superclass.enableHover.apply(this, [{
+            container: "body"
+        }]);
+    },
+
+    setSelected: function (b) {
+        this.element[b ? "addClass" : "removeClass"]("active");
+    }
+});
+$.shortcut('bi.relation_view_item', BI.RelationViewItem);/**
+ * 关联视图
+ *
+ * Created by GUY on 2015/12/22.
+ * @class BI.RelationView
+ * @extends BI.Widget
+ */
+BI.RelationView = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#c4c6c6",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.RelationView.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _calculateWidths: function () {
+        var widths = [];
+        BI.each(this.views, function (i, items) {
+            BI.each(items, function (j, obj) {
+                if (!widths[j]) {
+                    widths[j] = BI.MIN;
+                }
+                widths[j] = Math.max(widths[j], obj.getWidth());
+            })
+        });
+        return widths;
+    },
+
+    _calculateHeights: function () {
+        var heights = BI.makeArray(BI.size(this.views), BI.MIN);
+        BI.each(this.views, function (i, items) {
+            BI.each(items, function (j, obj) {
+                heights[i] = Math.max(heights[i], obj.getHeight());
+            })
+        });
+        return heights;
+    },
+
+    _hoverIn: function (target) {
+        var self = this, c = this._const;
+        BI.each(this.relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                if (relation[0].primary.value === target || relation[0].foreign.value === target) {
+                    self.lines[start][end].attr("stroke", c.selectLineColor).toFront();
+                    self.storeViews[start].setValue(relation[0].primary.value);
+                    self.storeViews[end].setValue(relation[0].foreign.value);
+                }
+            });
+        });
+    },
+
+    _hoverOut: function (target) {
+        var self = this, c = this._const;
+        BI.each(this.relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                if (relation[0].primary.value === target || relation[0].foreign.value === target) {
+                    self.lines[start][end].attr("stroke", c.lineColor);
+                    self.storeViews[start].setValue([]);
+                    self.storeViews[end].setValue([]);
+                }
+            });
+        });
+    },
+
+    previewRelationTables: function(relationTables, show) {
+        if (!show) {
+            BI.each(this.storeViews, function (i, view) {
+                view.toggleRegion(true);
+                view.setPreviewSelected(false);
+            });
+            BI.each(this.lines, function (i, lines) {
+                BI.each(lines, function (j, line) {
+                    line.show();
+                });
+            });
+            return;
+        }
+        BI.each(this.storeViews, function (id, view) {
+            if (!relationTables.contains(id)) {
+                view.toggleRegion(false);
+            } else {
+                view.setPreviewSelected(true);
+            }
+        });
+        BI.each(this.lines, function (id, lines) {
+            BI.each(lines, function (cId, line) {
+                if (!relationTables.contains(id) || !relationTables.contains(cId)) {
+                    line.hide();
+                }
+            });
+        });
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options, c = this._const;
+        o.items = items || [];
+        this.empty();
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+
+        //算出所有的区域和关联
+        var regions = this.regions = {}, relations = this.relations = {};
+        BI.each(items, function (i, item) {
+            var pr = item.primary.region, fr = item.foreign && item.foreign.region;
+            if (pr && !relations[pr]) {
+                relations[pr] = {};
+            }
+            if (pr && fr && !relations[pr][fr]) {
+                relations[pr][fr] = [];
+            }
+            if (pr && !regions[pr]) {
+                regions[pr] = [];
+            }
+            if (fr && !regions[fr]) {
+                regions[fr] = [];
+            }
+            if (pr && !BI.deepContains(regions[pr], item.primary)) {
+                regions[pr].push(item.primary);
+            }
+            if (fr && !BI.deepContains(regions[fr], item.foreign)) {
+                regions[fr].push(item.foreign);
+            }
+            pr && fr && relations[pr][fr].push(item);
+        });
+        //求拓扑
+        var topology = [];
+        var rs = BI.clone(regions), store = {};
+        while (!BI.isEmpty(rs)) {
+            var clone = BI.clone(rs);
+            BI.each(o.items, function (i, item) {
+                if (!store[item.primary.region]) {
+                    delete clone[item.foreign && item.foreign.region];
+                }
+            });
+            topology.push(BI.keys(clone));
+            BI.extend(store, clone);
+            BI.each(clone, function (k, v) {
+                delete rs[k];
+            });
+        }
+        //构建视图
+        var views = this.views = {}, storeViews = this.storeViews = {}, indexes = this.indexes = {};
+        var verticals = [];
+        BI.each(topology, function (i, items) {
+            if (!views[i]) {
+                views[i] = {};
+            }
+            var horizontal = [];
+            BI.each(items, function (j, region) {
+                var items = regions[region];
+                views[i][j] = storeViews[region] = BI.createWidget({
+                    type: "bi.relation_view_region_container",
+                    value: region,
+                    header: items[0].regionTitle,
+                    text: items.length > 0 ? items[0].regionText : "",
+                    handler: items.length > 0 ? items[0].regionHandler : BI.emptyFn,
+                    items: items,
+                    belongPackage: items.length > 0 ? items[0].belongPackage : true
+                });
+                if (BI.isNotNull(items[0]) && BI.isNotNull(items[0].keyword)) {
+                    views[i][j].doRedMark(items[0].keyword);
+                }
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_IN, function (v) {
+                    self._hoverIn(v);
+                });
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, function (v) {
+                    self._hoverOut(v);
+                });
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_PREVIEW, function (v) {
+                    self.fireEvent(BI.RelationView.EVENT_PREVIEW, region, v);
+                });
+                indexes[region] = {i: i, j: j};
+                horizontal.push(views[i][j]);
+            });
+            verticals.push({
+                type: "bi.horizontal",
+                items: horizontal
+            })
+        });
+
+        //求每一行的高度
+        var heights = this._calculateHeights();
+
+        //求每一列的宽度
+        var widths = this._calculateWidths();
+
+        //求相对宽度和高度
+        var offsetWidths = [0], offsetHeights = [0];
+        BI.each(heights, function (i, h) {
+            if (i === 0) {
+                return;
+            }
+            offsetHeights[i] = offsetHeights[i - 1] + heights[i - 1];
+        });
+        BI.each(widths, function (i, w) {
+            if (i === 0) {
+                return;
+            }
+            offsetWidths[i] = offsetWidths[i - 1] + widths[i - 1];
+        });
+
+        //画线
+        var lines = this.lines = {};//缓存所有的线
+        BI.each(relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                var startIndex = indexes[start], endIndex = indexes[end];
+                var top = 0, right = 1, bottom = 2, left = 3;
+                var startDirection = bottom, endDirection = top;
+                // if (startIndex.j > endIndex.j) {
+                //     startDirection = left;
+                //     endDirection = right;
+                // } else if (startIndex.j < endIndex.j) {
+                //     startDirection = right;
+                //     endDirection = left;
+                // } else if (startIndex.i < endIndex.i) {
+                //     startDirection = bottom;
+                //     endDirection = top;
+                // } else if (startIndex.i > endIndex.i) {
+                //     startDirection = top;
+                //     endDirection = bottom;
+                // }
+                var draw = function (i, j, direction, isForeign) {
+                    var x = offsetWidths[j] + (widths[j] - views[i][j].getWidth()) / 2;
+                    var y = offsetHeights[i] + (heights[i] - views[i][j].getHeight()) / 2;
+                    var path = "", position;
+                    switch (direction) {
+                        case top:
+                            position = isForeign ? views[i][j].getTopRightPosition() : views[i][j].getTopLeftPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + x + "," + (y - 10);
+                            y -= 10;
+                            break;
+                        case right:
+                            position = views[i][j].getRightPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + (x + 10) + "," + y;
+                            x += 10;
+                            break;
+                        case bottom:
+                            position = views[i][j].getBottomPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + x + "," + (y + 10);
+                            y += 10;
+                            break;
+                        case left:
+                            position = views[i][j].getLeftPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + (x - 10) + "," + y;
+                            x -= 10;
+                            break;
+                    }
+                    return {x: x, y: y, path: path};
+                };
+                var path = "";
+                var si = draw(startIndex.i, startIndex.j, startDirection);
+                var ei = draw(endIndex.i, endIndex.j, endDirection, true);
+                path += si.path + ei.path;
+                if (!lines[start]) {
+                    lines[start] = {};
+                }
+                path += "M" + si.x + "," + si.y + "L" + ei.x + "," + ei.y;
+                var line = lines[start][end] = self.svg.path(path)
+                    .attr({"stroke": c.lineColor, "stroke-width": "2"})
+                    .hover(function () {
+                        line.attr("stroke", c.selectLineColor).toFront();
+                        storeViews[start].setValue(relation[0].primary.value);
+                        storeViews[end].setValue(relation[0].foreign.value);
+                    }, function () {
+                        line.attr("stroke", c.lineColor);
+                        storeViews[start].setValue([]);
+                        storeViews[end].setValue([]);
+                    });
+            });
+        });
+        var container = BI.createWidget();
+        BI.createWidget({
+            type: "bi.vertical",
+            element: container,
+            items: verticals
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container,
+            items: [{
+                el: this.svg,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            scrollable: true,
+            element: this,
+            items: [container]
+        });
+    }
+});
+BI.RelationView.EVENT_CHANGE = "RelationView.EVENT_CHANGE";
+BI.RelationView.EVENT_PREVIEW = "EVENT_PREVIEW";
+$.shortcut('bi.relation_view', BI.RelationView);/**
+ * Created by Young's on 2017/3/10.
+ */
+BI.RelationViewRegionContainer = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewRegionContainer.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-region-container",
+            width: 150
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewRegionContainer.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.region = BI.createWidget({
+            type: "bi.relation_view_region",
+            value: o.value,
+            header: o.header,
+            text: o.text,
+            handler: o.handler,
+            items: o.items,
+            belongPackage: o.belongPackage
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_PREVIEW, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_PREVIEW, v);
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_HOVER_IN, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_IN, v);
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_HOVER_OUT, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, v);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.region],
+            width: this.region.getWidth(),
+            height: this.region.getHeight()
+        });
+    },
+
+    doRedMark: function () {
+        this.region.doRedMark.apply(this.region, arguments);
+    },
+
+    unRedMark: function () {
+        this.region.unRedMark.apply(this.region, arguments);
+    },
+
+    getWidth: function () {
+        return this.region.getWidth();
+    },
+
+    getHeight: function () {
+        return this.region.getHeight();
+    },
+
+    //获取上方开始划线的位置
+    getTopLeftPosition: function () {
+        return this.region.getTopLeftPosition();
+    },
+
+    getTopRightPosition: function () {
+        return this.region.getTopRightPosition();
+    },
+
+    getBottomPosition: function () {
+        return this.region.getBottomPosition();
+    },
+
+    getLeftPosition: function () {
+        return this.region.getLeftPosition();
+    },
+
+    getRightPosition: function () {
+        return this.region.getRightPosition();
+    },
+
+    setValue: function (v) {
+        this.region.setValue(v);
+    },
+
+    toggleRegion: function (v) {
+        v === true ? this.region.element.fadeIn() : this.region.element.fadeOut();
+    },
+
+    setPreviewSelected: function(v) {
+        this.region.setPreviewSelected(v);
+    }
+});
+BI.RelationViewRegionContainer.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN";
+BI.RelationViewRegionContainer.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT";
+BI.RelationViewRegionContainer.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW";
+$.shortcut("bi.relation_view_region_container", BI.RelationViewRegionContainer);/**
+ * 关联视图
+ *
+ * Created by GUY on 2015/12/23.
+ * @class BI.RelationViewRegion
+ * @extends BI.BasicButton
+ */
+BI.RelationViewRegion = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewRegion.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-region cursor-pointer",
+            width: 150,
+            text: "",
+            value: "",
+            header: "",
+            items: [],
+            belongPackage: true
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewRegion.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.preview = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "relation-table-preview-font",
+            width: 25,
+            height: 25,
+            stopPropagation: true
+        });
+        this.preview.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.RelationViewRegion.EVENT_PREVIEW, this.isSelected());
+        });
+
+        this.title = BI.createWidget({
+            type: "bi.label",
+            height: 25,
+            width: 70,
+            text: o.text,
+            value: o.value,
+            textAlign: "left"
+        });
+        //title放body上
+        if (BI.isKey(o.header)) {
+            this.title.setTitle(o.header, {
+                container: "body"
+            })
+        }
+
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            items: this._createItems(o.items),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [{
+                type: "bi.vertical",
+                cls: "relation-view-region-container " + (o.belongPackage ? "" : "other-package"),
+                items: [{
+                    type: "bi.vertical_adapt",
+                    cls: "relation-view-region-title",
+                    items: [this.preview, this.title]
+                }, this.button_group]
+            }],
+            hgap: 25,
+            vgap: 20
+        })
+    },
+
+    _createItems: function (items) {
+        var self = this;
+        return BI.map(items, function (i, item) {
+            return BI.extend(item, {
+                type: "bi.relation_view_item",
+                hoverIn: function () {
+                    self.setValue(item.value);
+                    self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_IN, item.value);
+                },
+                hoverOut: function () {
+                    self.setValue([]);
+                    self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_OUT, item.value);
+                }
+            })
+        });
+    },
+
+    doRedMark: function () {
+        this.title.doRedMark.apply(this.title, arguments);
+    },
+
+    unRedMark: function () {
+        this.title.unRedMark.apply(this.title, arguments);
+    },
+
+    getWidth: function () {
+        return this.options.width;
+    },
+
+    getHeight: function () {
+        return this.button_group.getAllButtons().length * 25 + 25 + 2 * 20 + 3;
+    },
+
+    //获取上方开始划线的位置
+    getTopLeftPosition: function () {
+        return {
+            x: 25 + 10,
+            y: 20
+        }
+    },
+
+    getTopRightPosition: function () {
+        return {
+            x: this.getWidth() - 25 - 10,
+            y: 20
+        }
+    },
+
+    getBottomPosition: function () {
+        return {
+            x: 25 + 10,
+            y: this.getHeight() - 20
+        }
+    },
+
+    getLeftPosition: function () {
+        return {
+            x: 25,
+            y: 20 + 10
+        }
+    },
+
+    getRightPosition: function () {
+        return {
+            x: this.getWidth() - 25,
+            y: 20 + 10
+        }
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    setPreviewSelected: function(v) {
+        this.preview.setSelected(v);
+    }
+});
+BI.RelationViewRegion.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN";
+BI.RelationViewRegion.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT";
+BI.RelationViewRegion.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW";
+$.shortcut('bi.relation_view_region', BI.RelationViewRegion);/**
+ * 完成搜索功能模块
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearcher
+ * @extends BI.Widget
+ */
+BI.SelectDataSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-searcher",
+            packages: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.packagePane = BI.createWidget({
+            type: "bi.select_data_switcher",
+            packages: o.packages,
+            itemsCreator: function (op) {
+                op.packageId = self.getPackageId();
+                if (!op.packageId) {
+                    return;
+                }
+                o.itemsCreator.apply(self, arguments);
+            }
+        });
+        this.packagePane.on(BI.SelectDataSwitcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_PACKAGE, arguments);
+        });
+        this.packagePane.on(BI.SelectDataSwitcher.EVENT_CLICK_ITEM, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcherPane = BI.createWidget({
+            type: "bi.select_data_search_result_pane",
+            itemsCreator: function (op) {
+                op.packageId = self.getPackageId();
+                if (!op.packageId) {
+                    return;
+                }
+                o.itemsCreator.apply(self, arguments);
+            }
+        });
+        this.searcherPane.on(BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE, function () {
+            self.searcher.doSearch();
+        });
+        this.searcherPane.on(BI.SelectDataSearchResultPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(BI.extend(op, {
+                    packageId: self.getPackageId(),
+                    searchType: self.searcherPane.getSegmentValue()
+                }), function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+            popup: this.searcherPane,
+            adapter: this.packagePane
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.packagePane]
+        })
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataSearcher.superclass.setEnable.apply(this, arguments);
+        this.packagePane.setEnable(v)
+    },
+
+    setPackage: function (pId) {
+        this.packagePane.setPackage(pId);
+    },
+
+    getPackageId: function () {
+        return this.packagePane.getPackageId();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populatePackages: function (packages) {
+        this.options.packages = packages;
+        this.packagePane.populatePackages(packages);
+        this.searcher.stopSearch();
+        this.populate();
+    },
+
+    populate: function () {
+        this.packagePane.populate.apply(this.packagePane, arguments);
+    }
+});
+BI.SelectDataSearcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+BI.SelectDataSearcher.EVENT_CLICK_PACKAGE = "EVENT_CLICK_PACKAGE";
+$.shortcut('bi.select_data_searcher', BI.SelectDataSearcher);/**
+ * 搜索结果面板
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearchResultPane
+ * @extends BI.Widget
+ */
+BI.SelectDataSearchResultPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearchResultPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-search-result-pane bi-searcher-view",
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSearchResultPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.segment = BI.createWidget({
+            type: "bi.select_data_search_segment",
+            cls: "search-result-toolbar"
+        });
+        this.segment.on(BI.SelectDataSearchSegment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE);
+        });
+
+        this.resultPane = BI.createWidget({
+            type: "bi.searcher_view",
+            matcher: {
+                type: "bi.select_data_tree",
+                itemsCreator: o.itemsCreator
+            },
+            searcher: {
+                type: "bi.select_data_tree",
+                itemsCreator: o.itemsCreator
+            }
+        });
+        this.resultPane.on(BI.SearcherView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchResultPane.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.segment,
+                height: 60
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 2
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 1
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.resultPane,
+                    left: 0,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+    },
+
+    startSearch: function () {
+
+    },
+
+    stopSearch: function () {
+
+    },
+
+    empty: function () {
+        this.resultPane.empty();
+    },
+
+    populate: function (searchResult, matchResult, keyword) {
+        this.resultPane.populate.apply(this.resultPane, arguments);
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getSegmentValue: function () {
+        return this.segment.getValue();
+    },
+
+    getValue: function () {
+        return this.resultPane.getValue();
+    }
+});
+BI.SelectDataSearchResultPane.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE = "EVENT_SEARCH_TYPE_CHANGE";
+$.shortcut('bi.select_data_search_result_pane', BI.SelectDataSearchResultPane);/**
+ * search面板选项栏
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearchSegment
+ * @extends BI.Widget
+ */
+BI.SelectDataSearchSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearchSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-search-segment",
+            height: 60
+        });
+    },
+
+    //创建所有数据和业务包选项
+    _createSectionTab: function () {
+        var self = this;
+        this.pack = BI.createWidget({
+            type: "bi.line_segment_button",
+            height: 24,
+            selected: true,
+            text: BI.i18nText("BI-Current_Package"),
+            value: BI.SelectDataSearchSegment.SECTION_PACKAGE
+        });
+        this.all = BI.createWidget({
+            type: "bi.line_segment_button",
+            height: 24,
+            text: BI.i18nText("BI-All_Data"),
+            value: BI.SelectDataSearchSegment.SECTION_ALL
+        });
+
+        this.button_group = BI.createWidget({
+            type: "bi.line_segment",
+            height: 25,
+            items: [this.all, this.pack]
+        });
+
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchSegment.EVENT_CHANGE);
+        });
+        return this.button_group;
+    },
+
+    _createSegmet: function () {
+        var self = this;
+        this.segment = BI.createWidget({
+            type: "bi.segment",
+            height: 20,
+            cls: "search-segment-field-table",
+            items: [{
+                text: BI.i18nText("BI-Basic_Field"),
+                selected: true,
+                value: BI.SelectDataSearchSegment.SECTION_FIELD
+            }, {
+                text: BI.i18nText("BI-Basic_Table"),
+                value: BI.SelectDataSearchSegment.SECTION_TABLE
+            }]
+        });
+        this.segment.on(BI.Segment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchSegment.EVENT_CHANGE);
+        });
+        return this.segment;
+    },
+
+    _init: function () {
+        BI.SelectDataSearchSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this._createSectionTab(), {
+                type: "bi.absolute",
+                height: 35,
+                items: [{
+                    el: this._createSegmet(),
+                    top: 10,
+                    right: 10,
+                    left: 10,
+                    bottom: 5
+                }]
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        var self = this;
+        BI.each([BI.SelectDataSearchSegment.SECTION_ALL,
+            BI.SelectDataSearchSegment.SECTION_PACKAGE], function (i, key) {
+            if (key & v) {
+                self.button_group.setValue(key & v);
+            }
+        });
+        BI.each([BI.SelectDataSearchSegment.SECTION_FIELD,
+            BI.SelectDataSearchSegment.SECTION_TABLE], function (i, key) {
+            if (key & v) {
+                self.segment.setValue(key & v);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.button_group.getValue()[0] | this.segment.getValue()[0]
+    }
+});
+
+BI.extend(BI.SelectDataSearchSegment, {
+    SECTION_ALL: 0x1,
+    SECTION_PACKAGE: 0x10,
+    SECTION_FIELD: 0x100,
+    SECTION_TABLE: 0x1000
+});
+BI.SelectDataSearchSegment.EVENT_CHANGE = "SelectDataSearchSegment.EVENT_CHANGE";
+$.shortcut('bi.select_data_search_segment', BI.SelectDataSearchSegment);/**
+ * 切换业务包
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSwitcher
+ * @extends BI.Widget
+ */
+BI.SelectDataSwitcher = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSwitcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-switcher",
+            packages: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSwitcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.combo = BI.createWidget({
+            type: "bi.single_tree_combo",
+            height: 25,
+            items: o.packages
+        });
+        this.combo.on(BI.SingleTreeCombo.EVENT_CHANGE, function () {
+            self.tree.populate();
+            self.fireEvent(BI.SelectDataSwitcher.EVENT_CHANGE, arguments);
+        });
+
+        this.tree = BI.createWidget({
+            type: "bi.select_data_tree",
+            itemsCreator: function () {
+                var args = Array.prototype.slice.call(arguments, 0);
+                args[0].packageId = self.getPackageId();
+                o.itemsCreator.apply(self, args);
+            }
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSwitcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    hgap: 10,
+                    items: [{
+                        el: this.combo
+                    }]
+                },
+                height: 30
+            }, {
+                el: this.tree
+            }]
+        });
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataSwitcher.superclass.setEnable.apply(this, arguments);
+        this.tree.setEnable(v)
+    },
+
+
+    setPackage: function (pId) {
+        this.combo.setValue([pId]);
+        this.tree.populate();
+    },
+
+    getPackageId: function () {
+        return this.combo.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    populatePackages: function (pacakges) {
+        this.options.packages = pacakges;
+        var pId = this.getPackageId();
+        this.combo.populate(pacakges);
+        if (BI.isKey(pId)) {
+            this.combo.setValue(pId);
+        }
+    }
+});
+BI.SelectDataSwitcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+BI.SelectDataSwitcher.EVENT_CHANGE = "SelectDataSwitcher.EVENT_CHANGE";
+$.shortcut('bi.select_data_switcher', BI.SelectDataSwitcher);/**
+ * 字段列表展开Expander
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataExpander
+ * @extends BI.Widget
+ */
+BI.SelectDataExpander = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-expander",
+            el: {},
+            popup: {
+                items: [],
+                itemsCreator: BI.emptyFn
+            }
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataExpander.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el);
+        this.expander = BI.createWidget({
+            type: "bi.expander",
+            element: this,
+            isDefaultInit: false,
+            el: this.trigger,
+            popup: BI.extend({
+                type: "bi.select_data_loader"
+            }, o.popup)
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.expander.on(BI.Expander.EVENT_EXPAND, function(){
+
+        });
+        this.expander.on(BI.Expander.EVENT_COLLAPSE, function(){
+            this.getView().hideView();
+        });
+        this.expander.on(BI.Expander.EVENT_AFTER_INIT, function () {
+            this.getView().populate();
+        });
+        this.expander.on(BI.Expander.EVENT_CHANGE, function () {
+            self.trigger.setValue(this.getValue());
+        });
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataExpander.superclass.setEnable.apply(this, arguments)
+        this.expander.setEnable(v);
+        this.trigger.setEnable(v)
+    },
+
+    doBehavior: function () {
+        this.trigger.doRedMark.apply(this.trigger, arguments);
+        this.expander.doBehavior.apply(this.expander, arguments);
+    },
+
+    setValue: function (v) {
+        this.expander.setValue(v);
+    },
+
+    getValue: function () {
+        return this.expander.getValue();
+    },
+
+    showView: function(b){
+        this.expander.showView();
+    },
+
+    hideView: function(){
+        this.expander.hideView();
+    },
+
+    isExpanded: function () {
+        return this.expander.isExpanded();
+    },
+
+    getAllLeaves: function () {
+        return this.expander.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.expander.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.expander.getNodeByValue(value);
+    }
+});
+$.shortcut("bi.select_data_expander", BI.SelectDataExpander);/**
+ * 字段列表
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataLoader
+ * @extends BI.Widget
+ */
+BI.SelectDataLoader = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-loader",
+            items: [],
+            el: {},
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataLoader.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.loader = BI.createWidget({
+            type: "bi.loader",
+            isDefaultInit: false,
+            element: this,
+            items: o.items,
+            itemsCreator: o.itemsCreator,
+            el: BI.extend({
+                type: "bi.button_tree",
+                behaviors: {
+                    redmark: function () {
+                        return true;
+                    }
+                },
+                chooseType: BI.Selection.Multi,
+                layouts: [{
+                    type: "bi.vertical",
+                    hgap: 0,
+                    vgap: 0
+                }]
+            }, o.el)
+        });
+        this.loader.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                if (ob.isSelected()) {
+                    var index = this.getIndexByValue(val);
+                    if (index > -1) {
+                        var alls = this.getAllButtons();
+                        if (index - 1 >= 0) {
+                            if (BI.isNotNull(alls[index - 1]) && BI.isFunction(alls[index - 1].isSelected)
+                                && alls[index - 1].isSelected()) {
+                                alls[index - 1].setBottomLineVisible();
+                                ob.setTopLineVisible();
+                            }
+                        }
+                        if (index + 1 <= alls.length - 1) {
+                            if (BI.isNotNull(alls[index + 1]) && BI.isFunction(alls[index + 1].isSelected)
+                                && alls[index + 1].isSelected()) {
+                                alls[index + 1].setTopLineVisible();
+                                ob.setBottomLineVisible();
+                            }
+                        }
+                    }
+                } else {
+                    var index = this.getIndexByValue(val);
+                    if (index > -1) {
+                        var alls = this.getAllButtons();
+                        if (index - 1 >= 0) {
+                            if (BI.isNotNull(alls[index - 1]) && BI.isFunction(alls[index - 1].isSelected)
+                                && alls[index - 1].isSelected()) {
+                                alls[index - 1].setBottomLineInVisible();
+                            }
+                        }
+                        if (index + 1 <= alls.length - 1) {
+                            if (BI.isNotNull(alls[index + 1]) && BI.isFunction(alls[index + 1].isSelected)
+                                && alls[index + 1].isSelected()) {
+                                alls[index + 1].setTopLineInVisible();
+                            }
+                        }
+                    }
+                }
+                self.fireEvent(BI.SelectDataLoader.EVENT_CHANGE);
+            }
+        })
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataLoader.superclass.setEnable.apply(this, arguments);
+        this.loader.setEnable(v)
+    },
+
+    doBehavior: function () {
+        this.loader.doBehavior.apply(this.loader, arguments);
+    },
+
+    populate: function () {
+        this.loader.populate.apply(this.loader, arguments);
+    },
+
+    getAllButtons: function(){
+        return this.loader.getAllButtons();
+    },
+
+    showView: function(b){
+        BI.each(this.loader.getAllButtons(),function(i, button){
+            button.showView && button.showView(b);
+        })
+    },
+
+    hideView: function(b){
+        BI.each(this.loader.getAllButtons(),function(i, button){
+            button.hideView && button.hideView(b);
+        })
+    },
+
+    setValue: function (v) {
+        this.loader.setValue(v);
+    },
+
+    getValue: function () {
+        return this.loader.getValue();
+    },
+
+    empty: function () {
+        this.loader.empty();
+    }
+});
+BI.SelectDataLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_data_loader", BI.SelectDataLoader);/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectDataLevelNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevelNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevelNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level0-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 0,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        var title = this.options.title;
+        var warningTitle = this.options.warningTitle;
+        this.options.title = "";
+        this.options.warningTitle = "";
+        BI.SelectDataLevelNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            title: title,
+            warningTitle: warningTitle,
+            disabled: o.disabled,
+            py: o.py
+        });
+        this.tip = BI.createWidget({
+            type: "bi.label",
+            cls: "select-data-selected-count-label",
+            whiteSpace: "nowrap",
+            width: 25,
+            height: o.height
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }, {
+                width: 25,
+                el: this.tip
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevelNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevelNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevelNode.superclass.setValue.apply(this, arguments);
+        if (BI.isEmpty(items)) {
+            this.tip.setText("");
+        } else {
+            this.tip.setText("(" + items.length + ")");
+        }
+        this.tip.setTitle(items.toString());
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevelNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+        this.text.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level_node", BI.SelectDataLevelNode);/**
+ * Created by GUY on 2015/9/15.
+ * @class BI.SelectDataLevel1DateNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevel1DateNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevel1DateNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level1-date-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 1,
+            open: false,
+            height: 25
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-group-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-group-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-group-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-group-font";
+            default:
+                return "select-data-field-date-group-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevel1DateNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget({
+            type: "bi.icon_text_item",
+            cls: this._getFieldClass(o.fieldType),
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height,
+            textLgap: 10,
+            textRgap: 5
+        });
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                el: this.button
+            }, {
+                el: this.checkbox,
+                width: 25
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevel1DateNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevel1DateNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevel1DateNode.superclass.setValue.apply(this, arguments);
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevel1DateNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level1_date_node", BI.SelectDataLevel1DateNode);/**
+ * Created by GUY on 2015/9/15.
+ * @class BI.SelectDataLevel2DateNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevel2DateNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevel2DateNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level2-date-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 2,
+            open: false,
+            height: 25
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-group-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-group-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-group-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-group-font";
+            default:
+                return "select-data-field-date-group-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevel2DateNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget({
+            type: "bi.icon_text_item",
+            cls: this._getFieldClass(o.fieldType),
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height,
+            textLgap: 10,
+            textRgap: 5
+        });
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                el: this.button
+            }, {
+                el: this.checkbox,
+                width: 25
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevel2DateNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevel2DateNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevel2DateNode.superclass.setValue.apply(this, arguments);
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevel2DateNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level2_date_node", BI.SelectDataLevel2DateNode);/**
+ * 字段列表展开Expander
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataTree
+ * @extends BI.Widget
+ */
+BI.SelectDataTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-tree",
+            el: {},
+            expander: {},
+            items: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.select_data_expander",
+                el: {},
+                popup: {
+                    type: "bi.select_data_tree"
+                }
+            }, o.expander),
+            items: o.items,
+            itemsCreator: o.itemsCreator,
+
+            el: BI.extend({
+                type: "bi.select_data_loader"
+            }, o.el)
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.tree.on(BI.CustomTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataTree.EVENT_CHANGE, arguments);
+        })
+    },
+
+
+    setEnable: function (v) {
+        BI.SelectDataTree.superclass.setEnable.apply(this, arguments);
+        this.tree.setEnable(v)
+    },
+
+    showView: function(b){
+        BI.each(this.tree.getAllButtons(),function(i, button){
+            button.showView && button.showView(b);
+        })
+    },
+
+    hideView: function(b){
+        BI.each(this.tree.getAllButtons(),function(i, button){
+            button.hideView && button.hideView(b);
+        })
+    },
+
+    getAllButtons: function(){
+        return this.tree.getAllButtons();
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    empty: function () {
+
+    },
+
+    populate: function (items) {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        //这里需要去重,因为很有可能expander中保存了之前的value值
+        return BI.uniq(this.tree.getValue());
+    }
+});
+BI.SelectDataTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_data_tree", BI.SelectDataTree);/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectDataLevelItem
+ * @extends BI.Single
+ */
+BI.SelectDataLevelItem = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevelItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level0-item",
+            height: 25,
+            hgap: 0,
+            layer: 1,
+            fieldType: BICst.COLUMN.STRING,
+            lgap: 0,
+            rgap: 0
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-font";
+            default:
+                return "select-data-field-number-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevelItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button = BI.createWidget({
+            type: "bi.blank_icon_text_item",
+            trigger: "mousedown",
+            cls: "select-data-level0-item-button " + this._getFieldClass(o.fieldType),
+            blankWidth: o.layer * 20,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: 25,
+            textLgap: 10,
+            textRgap: 5
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.getValue(), self);
+        });
+
+        this.topLine = BI.createWidget({
+            type: "bi.layout",
+            height: 0,
+            cls: "select-data-top-line"
+        });
+        this.bottomLine = BI.createWidget({
+            type: "bi.layout",
+            height: 0,
+            cls: "select-data-bottom-line"
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topLine,
+                top: 0,
+                left: o.lgap,
+                right: o.rgap
+            }, {
+                el: this.bottomLine,
+                bottom: 0,
+                left: o.lgap,
+                right: o.rgap
+            }, {
+                el: this.button,
+                top: 0,
+                left: o.lgap,
+                right: o.rgap
+            }]
+        });
+        this.topLine.invisible();
+        this.bottomLine.invisible();
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataLevelItem.superclass.setEnable.apply(this, arguments)
+        this.button.setEnable(v);
+        try {
+            this.button.element.draggable(v ? "enable" : "disable");
+        } catch (e) {
+
+        }
+        if (!v) {
+            this.setSelected(false);
+        }
+    },
+
+    isSelected: function () {
+        return this.button.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.button.setSelected(b);
+        if (!b) {
+            this.topLine.invisible();
+            this.bottomLine.invisible();
+            this.element.removeClass("select-data-item-top");
+            this.element.removeClass("select-data-item-bottom");
+        }
+    },
+
+    setTopLineVisible: function () {
+        this.topLine.visible();
+        this.element.addClass("select-data-item-top");
+    },
+
+    setTopLineInVisible: function () {
+        this.topLine.invisible();
+        this.element.removeClass("select-data-item-top");
+    },
+
+    setBottomLineVisible: function () {
+        this.bottomLine.visible();
+        this.element.addClass("select-data-item-bottom");
+    },
+
+    setBottomLineInVisible: function () {
+        this.bottomLine.invisible();
+        this.element.removeClass("select-data-item-bottom");
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doHighLight: function () {
+        this.button.doHighLight.apply(this.button, arguments);
+    },
+
+    unHighLight: function () {
+        this.button.unHighLight.apply(this.button, arguments);
+    }
+});
+
+$.shortcut("bi.select_data_level_item", BI.SelectDataLevelItem);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-first-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.first_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_first_plus_group_node", BI.SelectTreeFirstPlusGroupNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-last-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.last_tree_node_checkbox",
+            stopPropagation: true
+        })
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_last_plus_group_node", BI.SelectTreeLastPlusGroupNode);/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-mid-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.mid_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_mid_plus_group_node", BI.SelectTreeMidPlusGroupNode);/**
+ * @class BI.SelectTreeCombo
+ * @extends BI.Widget
+ */
+BI.SelectTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-combo",
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SelectTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.select_tree_popup",
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+
+
+$.shortcut("bi.select_tree_combo", BI.SelectTreeCombo);/**
+ * @class BI.SelectTreeExpander
+ * @extends BI.Widget
+ */
+BI.SelectTreeExpander = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreeExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-expander",
+            trigger: "click",
+            toggle: true,
+            direction: "bottom",
+            isDefaultInit: true,
+            el: {},
+            popup: {}
+        });
+    },
+
+    _init: function () {
+        BI.SelectTreeExpander.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget(BI.extend({stopPropagation: true}, o.el));
+        this.trigger.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.expander.setValue([]);
+                }
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.expander = BI.createWidget({
+            type: "bi.expander",
+            element: this,
+            trigger: o.trigger,
+            toggle: o.toggle,
+            direction: o.direction,
+            isDefaultInit: o.isDefaultInit,
+            el: this.trigger,
+            popup: o.popup
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.trigger.setSelected(false);
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        if (BI.contains(v, this.trigger.getValue())) {
+            this.trigger.setSelected(true);
+            this.expander.setValue([]);
+        } else {
+            this.trigger.setSelected(false);
+            this.expander.setValue(v);
+        }
+    },
+
+    getValue: function () {
+        if (this.trigger.isSelected()) {
+            return [this.trigger.getValue()];
+        }
+        return this.expander.getValue();
+    },
+
+    populate: function (items) {
+        this.expander.populate(items);
+    }
+});
+
+$.shortcut("bi.select_tree_expander", BI.SelectTreeExpander);/**
+ * @class BI.SelectTreePopup
+ * @extends BI.Pane
+ */
+
+BI.SelectTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            items: []
+        });
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {layer: layer};
+            node.id = node.id || BI.UUID();
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.select_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.select_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.select_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+                self._formatItems(node.children);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _init: function () {
+        BI.SelectTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.level_tree',
+            expander: {
+                type: "bi.select_tree_expander",
+                isDefaultInit: true
+            },
+            items: this._formatItems(BI.Tree.transformToTreeFormat(o.items)),
+            chooseType: BI.Selection.Single
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.SelectTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.SelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_tree_popup", BI.SelectTreePopup);/**
+ *
+ * Created by GUY on 2016/8/10.
+ * @class BI.SequenceTableDynamicNumber
+ * @extends BI.SequenceTableTreeNumber
+ */
+BI.SequenceTableDynamicNumber = BI.inherit(BI.SequenceTableTreeNumber, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableDynamicNumber.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-sequence-table-dynamic-number"
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableDynamicNumber.superclass._init.apply(this, arguments);
+    },
+
+    _formatNumber: function (nodes) {
+        var self = this, o = this.options;
+        var result = [];
+        var count = this._getStart(nodes);
+
+        function getLeafCount(node) {
+            var cnt = 0;
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    cnt += getLeafCount(child);
+                });
+                if (node.children.length > 1 && BI.isNotEmptyArray(node.values)) {
+                    cnt++;
+                }
+            } else {
+                cnt++;
+            }
+            return cnt;
+        }
+
+        var start = 0, top = 0;
+        BI.each(nodes, function (i, node) {
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    var cnt = getLeafCount(child);
+                    result.push({
+                        text: count++,
+                        start: start,
+                        top: top,
+                        cnt: cnt,
+                        index: index,
+                        height: cnt * o.rowSize
+                    });
+                    start += cnt;
+                    top += cnt * o.rowSize;
+                });
+                if (BI.isNotEmptyArray(node.values)) {
+                    result.push({
+                        text: BI.i18nText("BI-Summary_Values"),
+                        start: start++,
+                        top: top,
+                        cnt: 1,
+                        isSummary: true,
+                        height: o.rowSize
+                    });
+                    top += o.rowSize;
+                }
+            }
+        });
+        return result;
+    }
+});
+$.shortcut('bi.sequence_table_dynamic_number', BI.SequenceTableDynamicNumber);/**
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTableListNumber
+ * @extends BI.Widget
+ */
+BI.SequenceTableListNumber = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableListNumber.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table-list-number",
+            isNeedFreeze: false,
+            scrollTop: 0,
+            startSequence: 1,//开始的序号
+            headerRowSize: 25,
+            rowSize: 25,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: [],
+
+            pageSize: 20
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableListNumber.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.start = o.startSequence;
+        this.renderedCells = [];
+        this.renderedKeys = [];
+
+        this.header = BI.createWidget({
+            type: "bi.table_style_cell",
+            cls: "sequence-table-title-cell",
+            styleGetter: o.headerCellStyleGetter,
+            text: BI.i18nText("BI-Number_Index")
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            width: 60,
+            scrollable: false
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.container]
+        });
+
+        this.layout = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.header,
+                height: o.headerRowSize * o.header.length
+            }, {
+                el: this.scrollContainer
+            }]
+        });
+        this._populate();
+    },
+
+    _layout: function () {
+        var self = this, o = this.options;
+        var headerHeight = o.headerRowSize * o.header.length;
+        var items = this.layout.attr("items");
+        if (o.isNeedFreeze === false) {
+            items[0].height = 0;
+        } else if (o.isNeedFreeze === true) {
+            items[0].height = headerHeight;
+        }
+        this.layout.attr("items", items);
+        this.layout.resize();
+        this.container.setHeight(o.items.length * o.rowSize);
+        this.scrollContainer.element.scrollTop(o.scrollTop);
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+        var scrollTop = BI.clamp(o.scrollTop, 0, o.rowSize * o.items.length - (o.height - o.header.length * o.headerRowSize) + BI.DOM.getScrollWidth());
+        var start = Math.floor(scrollTop / o.rowSize);
+        var end = start + Math.floor((o.height - o.header.length * o.headerRowSize) / o.rowSize);
+        var renderedCells = [], renderedKeys = [];
+        for (var i = start, cnt = 0; i <= end && i < o.items.length; i++, cnt++) {
+            var index = BI.deepIndexOf(this.renderedKeys, this.start + i);
+            var top = i * o.rowSize;
+            if (index > -1) {
+                if (o.rowSize !== this.renderedCells[index]._height) {
+                    this.renderedCells[index]._height = o.rowSize;
+                    this.renderedCells[index].el.setHeight(o.rowSize);
+                }
+                if (this.renderedCells[index].top !== top) {
+                    this.renderedCells[index].top = top;
+                    this.renderedCells[index].el.element.css("top", top + "px");
+                }
+                renderedCells.push(this.renderedCells[index]);
+            } else {
+                var child = BI.createWidget(BI.extend({
+                    type: "bi.table_style_cell",
+                    cls: "sequence-table-number-cell",
+                    width: 60,
+                    height: o.rowSize,
+                    text: this.start + i,
+                    styleGetter: function (index) {
+                        return function () {
+                            return o.sequenceCellStyleGetter(self.start + i - 1);
+                        }
+                    }(cnt)
+                }));
+                renderedCells.push({
+                    el: child,
+                    left: 0,
+                    top: top,
+                    _height: o.rowSize
+                });
+            }
+            renderedKeys.push(this.start + i);
+        }
+
+        //已存在的, 需要添加的和需要删除的
+        var existSet = {}, addSet = {}, deleteArray = [];
+        BI.each(renderedKeys, function (i, key) {
+            if (BI.deepContains(self.renderedKeys, key)) {
+                existSet[i] = key;
+            } else {
+                addSet[i] = key;
+            }
+        });
+        BI.each(this.renderedKeys, function (i, key) {
+            if (BI.deepContains(existSet, key)) {
+                return;
+            }
+            if (BI.deepContains(addSet, key)) {
+                return;
+            }
+            deleteArray.push(i);
+        });
+        BI.each(deleteArray, function (i, index) {
+            self.renderedCells[index].el.destroy();
+        });
+        var addedItems = [];
+        BI.each(addSet, function (index) {
+            addedItems.push(renderedCells[index])
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: addedItems
+        });
+        this.renderedCells = renderedCells;
+        this.renderedKeys = renderedKeys;
+    },
+
+    _populate: function () {
+        this.header.populate();
+        this._layout();
+        this._calculateChildrenToRender();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        if (this.options.scrollTop !== scrollTop) {
+            this.options.scrollTop = scrollTop;
+            this.scrollContainer.element.scrollTop(scrollTop);
+        }
+    },
+
+    getVerticalScroll: function () {
+        return this.options.scrollTop;
+    },
+
+    setVPage: function (v) {
+        var o = this.options;
+        this.start = (v - 1) * o.pageSize + 1;
+    },
+
+    _restore: function () {
+        var o = this.options;
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+    },
+
+    restore: function () {
+        this._restore();
+    },
+
+    populate: function (items, header) {
+        var o = this.options;
+        if (items && items !== this.options.items) {
+            o.items = items;
+            this._restore();
+        }
+        if (header && header !== this.options.header) {
+            o.header = header;
+        }
+        this._populate();
+    }
+});
+$.shortcut('bi.sequence_table_list_number', BI.SequenceTableListNumber);/**
+ * 带有序号的表格
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTable
+ * @extends BI.Widget
+ */
+BI.SequenceTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table",
+            el: {
+                type: "bi.adaptive_table"
+            },
+
+            sequence: {},
+
+            isNeedResize: true,
+            isResizeAdapt: false,
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: BI.emptyFn,
+
+            columnSize: [],
+            minColumnSize: [],
+            maxColumnSize: [],
+            headerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: [],
+
+            headerCellStyleGetter: BI.emptyFn,
+            summaryCellStyleGetter: BI.emptyFn,
+            sequenceCellStyleGetter: BI.emptyFn,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: [],
+
+            showSequence: false,
+            startSequence: 1//开始的序号
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.sequence = BI.createWidget(o.sequence, {
+            type: "bi.sequence_table_list_number",
+            invisible: o.showSequence === false,
+            startSequence: o.startSequence,
+            isNeedFreeze: o.isNeedFreeze,
+            header: o.header,
+            items: o.items,
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+            width: 60,
+            height: o.height - BI.GridTableScrollbar.SIZE,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter
+        });
+        this.table = BI.createWidget(o.el, {
+            type: "bi.adaptive_table",
+            width: o.showSequence === true ? o.width - 60 : o.width,
+            height: o.height,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: o.columnSize,
+            minColumnSize: o.minColumnSize,
+            maxColumnSize: o.maxColumnSize,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter,
+
+            header: o.header,
+            items: o.items,
+            //交叉表头
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems
+        });
+
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function (scroll) {
+            if (self.sequence.getVerticalScroll() !== this.getVerticalScroll()) {
+                self.sequence.setVerticalScroll(this.getVerticalScroll());
+                self.sequence.populate();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+
+        this.htape = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.sequence,
+                left: 0,
+                top: 0
+            }, {
+                el: this.table,
+                top: 0,
+                left: o.showSequence === true ? 60 : 0
+            }]
+        });
+        this._populate();
+    },
+
+    _populate: function () {
+        var o = this.options;
+        this.sequence.attr({
+            items: o.items,
+            header: o.header,
+            crossItems: o.crossItems,
+            crossHeader: o.crossHeader
+        });
+        if (o.showSequence === true) {
+            this.sequence.setVisible(true);
+            this.table.element.css("left", "60px");
+            this.table.setWidth(o.width - 60);
+        } else {
+            this.sequence.setVisible(false);
+            this.table.element.css("left", "0px");
+            this.table.setWidth(o.width);
+        }
+    },
+
+    setWidth: function (width) {
+        BI.PageTable.superclass.setWidth.apply(this, arguments);
+        this.table.setWidth(this.options.showSequence ? width - 60 : width);
+    },
+
+    setHeight: function (height) {
+        BI.PageTable.superclass.setHeight.apply(this, arguments);
+        this.table.setHeight(height);
+        this.sequence.setHeight(height - BI.GridTableScrollbar.SIZE);
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    hasLeftHorizontalScroll: function () {
+        return this.table.hasLeftHorizontalScroll();
+    },
+
+    hasRightHorizontalScroll: function () {
+        return this.table.hasRightHorizontalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+        this.sequence.setVerticalScroll(scrollTop);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    setVPage: function (page) {
+        this.sequence.setVPage && this.sequence.setVPage(page);
+    },
+
+    setHPage: function (page) {
+        this.sequence.setHPage && this.sequence.setHPage(page);
+    },
+
+    attr: function () {
+        BI.SequenceTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+        this.sequence.attr.apply(this.sequence, arguments);
+    },
+
+    restore: function () {
+        this.table.restore();
+        this.sequence.restore();
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        if (items) {
+            o.items = items;
+        }
+        if (header) {
+            o.header = header;
+        }
+        if (crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        this._populate();
+        this.table.populate.apply(this.table, arguments);
+        this.sequence.populate.apply(this.sequence, arguments);
+        this.sequence.setVerticalScroll(this.table.getVerticalScroll());
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.SequenceTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.sequence_table', BI.SequenceTable);/**
+ * 简单的搜索功能
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSearcher
+ * @extends BI.Widget
+ */
+BI.SimpleSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-simple-searcher",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+
+        this.tree = BI.createWidget({
+            type: "bi.select_data_tree",
+            items: o.items,
+            el: {
+                el: {
+                    chooseType: o.chooseType
+                }
+            },
+            itemsCreator: o.itemsCreator
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSearcher.EVENT_CHANGE, arguments);
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(op, function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            popup: {
+                matcher: {
+                    type: "bi.select_data_tree",
+                    el: {
+                        el: {
+                            chooseType: o.chooseType
+                        }
+                    },
+                    itemsCreator: o.itemsCreator
+                },
+                searcher: {
+                    type: "bi.select_data_tree",
+                    el: {
+                        el: {
+                            chooseType: o.chooseType
+                        }
+                    },
+                    itemsCreator: o.itemsCreator
+                }
+            },
+            adapter: this.tree
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.tree]
+        })
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    }
+});
+BI.SimpleSearcher.EVENT_CHANGE = "SimpleSearcher.EVENT_CHANGE";
+$.shortcut('bi.simple_searcher', BI.SimpleSearcher);/**
+ * 完成搜索功能模块
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearcher
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-simple-select-data-searcher",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            popup: {},
+            adapter: {}
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+
+        this.tree = BI.createWidget(o.adapter, {
+            type: "bi.select_data_tree",
+            items: o.items,
+            el: {
+                el: {
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+                }
+            },
+            itemsCreator: o.itemsCreator
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcherPane = BI.createWidget(o.popup, {
+            type: "bi.simple_select_data_search_result_pane",
+            itemsCreator: o.itemsCreator
+        });
+        this.searcherPane.on(BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE, function () {
+            self.searcher.doSearch();
+        });
+        this.searcherPane.on(BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(BI.extend(op, {
+                    searchType: self.searcherPane.getSegmentValue()
+                }), function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            popup: this.searcherPane,
+            adapter: this.tree
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.tree]
+        })
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    }
+});
+BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+$.shortcut('bi.simple_select_data_searcher', BI.SimpleSelectDataSearcher);/**
+ * 搜索结果面板
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearchResultPane
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearchResultPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearchResultPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-select-data-search-result-pane bi-select-data-search-result-pane bi-searcher-view",
+            itemsCreator: BI.emptyFn,
+            segment: {}
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearchResultPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.segment = BI.createWidget(o.segment, {
+            type: "bi.simple_select_data_search_segment",
+            cls: "search-result-toolbar"
+        });
+        this.segment.on(BI.SimpleSelectDataSearchSegment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE);
+        });
+
+        this.resultPane = BI.createWidget({
+            type: "bi.searcher_view",
+            matcher: {
+                type: "bi.select_data_tree",
+                el: {
+                    el: {
+                        chooseType: BI.Selection.Single
+                    }
+                },
+                itemsCreator: o.itemsCreator
+            },
+            searcher: {
+                type: "bi.select_data_tree",
+                el: {
+                    el: {
+                        chooseType: BI.Selection.Single
+                    }
+                },
+                itemsCreator: o.itemsCreator
+            }
+        });
+
+        this.resultPane.on(BI.SearcherView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.segment,
+                height: 30
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 2
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 1
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.resultPane,
+                    left: 0,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+    },
+
+    empty: function () {
+        this.resultPane.empty();
+    },
+
+    populate: function (searchResult, matchResult, keyword) {
+        this.resultPane.populate.apply(this.resultPane, arguments);
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getSegmentValue: function () {
+        return this.segment.getValue();
+    },
+
+    getValue: function () {
+        return this.resultPane.getValue();
+    }
+});
+BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE = "EVENT_SEARCH_TYPE_CHANGE";
+BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.simple_select_data_search_result_pane', BI.SimpleSelectDataSearchResultPane);/**
+ * search面板选项栏
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearchSegment
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearchSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearchSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-select-data-search-segment",
+            height: 30,
+            items: [{
+                text: BI.i18nText("BI-Basic_Field"),
+                selected: true,
+                value: BI.SelectDataSearchSegment.SECTION_FIELD
+            }, {
+                text: BI.i18nText("BI-Basic_Table"),
+                value: BI.SelectDataSearchSegment.SECTION_TABLE
+            }]
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearchSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.segment = BI.createWidget({
+            type: "bi.segment",
+            height: 20,
+            cls: "search-segment-field-table",
+            items: o.items
+        });
+        this.segment.on(BI.Segment.EVENT_CHANGE, function(){
+            self.fireEvent(BI.SimpleSelectDataSearchSegment.EVENT_CHANGE);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [{
+                type: "bi.absolute",
+                height: o.height,
+                items: [{
+                    el: this.segment,
+                    top: 5,
+                    right: 10,
+                    left: 10,
+                    bottom: 5
+                }]
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        var self = this;
+        BI.each([BI.SelectDataSearchSegment.SECTION_FIELD,
+            BI.SelectDataSearchSegment.SECTION_TABLE], function (i, key) {
+            if (key & v) {
+                self.segment.setValue(key & v);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.segment.getValue()[0]
+    }
+});
+
+BI.SimpleSelectDataSearchSegment.EVENT_CHANGE = "SimpleSelectDataSearchSegment.EVENT_CHANGE";
+$.shortcut('bi.simple_select_data_search_segment', BI.SimpleSelectDataSearchSegment);/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SimpleSelectDataLevel0Node
+ * @extends BI.NodeButton
+ */
+BI.SimpleSelectDataLevel0Node = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataLevel0Node.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-simple-select-data-level0-node bi-list-item",
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SimpleSelectDataLevel0Node.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SimpleSelectDataLevel0Node.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SimpleSelectDataLevel0Node.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setEnable: function (b) {
+        BI.SimpleSelectDataLevel0Node.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.simple_select_data_level0_node", BI.SimpleSelectDataLevel0Node);/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SimpleSelectDataLevel1Node
+ * @extends BI.NodeButton
+ */
+BI.SimpleSelectDataLevel1Node = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataLevel1Node.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-simple-select-data-level1-node bi-list-item",
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SimpleSelectDataLevel1Node.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if(type ===  BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: 10
+            },{
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SimpleSelectDataLevel1Node.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SimpleSelectDataLevel1Node.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setEnable: function (b) {
+        BI.SimpleSelectDataLevel1Node.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.simple_select_data_level1_node", BI.SimpleSelectDataLevel1Node);/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.SingleSlider = BI.inherit(BI.Widget, {
+    _constant: {
+        EDITOR_WIDTH: 90,
+        EDITOR_HEIGHT: 30,
+        HEIGHT: 28,
+        SLIDER_WIDTH_HALF: 15,
+        SLIDER_WIDTH: 30,
+        SLIDER_HEIGHT: 30,
+        TRACK_HEIGHT: 24
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleSlider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider bi-slider-track"
+        });
+    },
+    _init: function () {
+        BI.SingleSlider.superclass._init.apply(this, arguments);
+
+        var self = this;
+        var c = this._constant;
+        this.enable = false;
+        this.value = "";
+
+        this.backgroundTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "background-track",
+            height: c.TRACK_HEIGHT
+        });
+        this.grayTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "gray-track",
+            height: 8
+        });
+        this.blueTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "blue-track",
+            height: 8
+        });
+        this.track = this._createTrackWrapper();
+
+        this.slider = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.slider.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));//直接对计算出来的百分数保留到小数点后一位,相当于分成了1000份。
+                self._setBlueTrack(significantPercent);
+                self._setLabelPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.label.setValue(v);
+                self.value = v;
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderPosition(significantPercent);
+                self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+            }
+        });
+        var sliderVertical = BI.createWidget({
+            type: "bi.vertical",
+            items: [{
+                type: "bi.absolute",
+                items: [this.slider]
+            }],
+            hgap: c.SLIDER_WIDTH_HALF,
+            height: c.SLIDER_HEIGHT
+        });
+        sliderVertical.element.click(function (e) {
+            if (self.enable) {
+                var offset = e.clientX - self.element.offset().left - c.SLIDER_WIDTH_HALF;
+                var trackLength = self.track.element[0].scrollWidth;
+                var percent = 0;
+                if (offset < 0) {
+                    percent = 0
+                }
+                if (offset > 0 && offset < (trackLength - c.SLIDER_WIDTH)) {
+                    percent = offset * 100 / self._getGrayTrackLength();
+                }
+                if (offset > (trackLength - c.SLIDER_WIDTH)) {
+                    percent = 100
+                }
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setAllPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.label.setValue(v);
+                self.value = v;
+                self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+            }
+        });
+        this.label = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            allowBlank: false,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.label.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));
+            self._setAllPosition(significantPercent);
+            self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+        });
+        this._setVisible(false);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.track,
+                            width: "100%",
+                            height: c.TRACK_HEIGHT
+                        }]
+                    }],
+                    hgap: 7,
+                    height: c.TRACK_HEIGHT
+                },
+                top: 33,
+                left: 0,
+                width: "100%"
+            }, {
+                el: sliderVertical,
+                top: 30,
+                left: 0,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [this.label]
+                    }],
+                    rgap: c.EDITOR_WIDTH,
+                    height: c.EDITOR_HEIGHT
+                },
+                top: 0,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _createTrackWrapper: function () {
+        return BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.backgroundTrack,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.grayTrack,
+                            top: 0,
+                            left: 0,
+                            width: "100%"
+                        }, {
+                            el: this.blueTrack,
+                            top: 0,
+                            left: 0,
+                            width: "0%"
+                        }]
+                    }],
+                    hgap: 8,
+                    height: 8
+                },
+                top: 8,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _checkValidation: function (v) {
+        return !(BI.isNull(v) || v < this.min || v > this.max)
+    },
+
+    _setBlueTrack: function (percent) {
+        this.blueTrack.element.css({"width": percent + "%"});
+    },
+
+    _setLabelPosition: function (percent) {
+        this.label.element.css({"left": percent + "%"});
+    },
+
+    _setSliderPosition: function (percent) {
+        this.slider.element.css({"left": percent + "%"});
+    },
+
+    _setAllPosition: function (percent) {
+        this._setSliderPosition(percent);
+        this._setLabelPosition(percent);
+        this._setBlueTrack(percent);
+    },
+
+    _setVisible: function (visible) {
+        this.slider.setVisible(visible);
+        this.label.setVisible(visible);
+    },
+
+    _getGrayTrackLength: function () {
+        return this.grayTrack.element[0].scrollWidth
+    },
+
+    _getValueByPercent: function (percent) {
+        var thousandth = BI.parseInt(percent * 10);
+        return (((this.max - this.min) * thousandth) / 1000 + this.min);
+    },
+
+    _getPercentByValue: function (v) {
+        return (v - this.min) * 100 / (this.max - this.min);
+    },
+
+    getValue: function () {
+        return this.value;
+    },
+
+    setValue: function (v) {
+        var value = BI.parseFloat(v);
+        if ((!isNaN(value))) {
+            if (this._checkValidation(value)) {
+                this.value = value;
+            }
+            if (value > this.max) {
+                this.value = this.max;
+            }
+            if (value < this.min) {
+                this.value = this.min;
+            }
+        }
+    },
+
+    setMinAndMax: function (v) {
+        var minNumber = BI.parseFloat(v.min);
+        var maxNumber = BI.parseFloat(v.max);
+        if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber > minNumber )) {
+            this.min = minNumber;
+            this.max = maxNumber;
+        }
+    },
+
+    reset: function () {
+        this._setVisible(false);
+        this.enable = false;
+        this.value = "";
+        this.min = 0;
+        this.max = 0;
+        this._setBlueTrack(0);
+    },
+
+    populate: function () {
+        if (!isNaN(this.min) && !isNaN(this.max)) {
+            this._setVisible(true);
+            this.enable = true;
+            this.label.setErrorText(BI.i18nText("BI-Please_Enter") + this.min + "-" + this.max + BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Basic_Number"));
+            if (BI.isNumeric(this.value) || BI.isNotEmptyString(this.value)) {
+                this.label.setValue(this.value);
+                this._setAllPosition(this._getPercentByValue(this.value));
+            } else {
+                this.label.setValue(this.max);
+                this._setAllPosition(100);
+            }
+        }
+    }
+});
+BI.SingleSlider.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.single_slider", BI.SingleSlider);/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.Slider = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Slider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider-slider"
+        });
+    },
+    _init: function () {
+        BI.extend(BI.Slider.superclass._init.apply(this, arguments));
+        this.slider = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "widget-slider-icon",
+            iconWidth: 30,
+            iconHeight: 30,
+            height: 30,
+            width: 30
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.slider,
+                top: 0,
+                left: -15
+            }],
+            width: 0,
+            height: 30
+        });
+    }
+});
+$.shortcut("bi.single_slider_slider", BI.Slider);/**
+ * @class BI.SingleTreeCombo
+ * @extends BI.Widget
+ */
+BI.SingleTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-combo",
+            trigger: {},
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget(BI.extend({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        }, o.trigger));
+
+        this.popup = BI.createWidget({
+            type: "bi.single_tree_popup",
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW, arguments);
+        });
+
+        this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.SingleTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+
+BI.SingleTreeCombo.EVENT_CHANGE = "SingleTreeCombo.EVENT_CHANGE";
+BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+$.shortcut("bi.single_tree_combo", BI.SingleTreeCombo);/**
+ * @class BI.SingleTreePopup
+ * @extends BI.Pane
+ */
+
+BI.SingleTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.level_tree',
+            expander: {
+                isDefaultInit: true
+            },
+            items: o.items,
+            chooseType: BI.Selection.Single
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SingleTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.SingleTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.SingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.single_tree_popup", BI.SingleTreePopup);/**
+ * @class BI.SingleTreeTrigger
+ * @extends BI.Trigger
+ */
+
+BI.SingleTreeTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreeTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-trigger",
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreeTrigger.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            element: this,
+            text: o.text,
+            items: o.items,
+            height: o.height
+        });
+    },
+
+    _checkTitle: function () {
+        var self = this, val = this.getValue();
+        BI.any(this.options.items, function (i, item) {
+            if (val.contains(item.value)) {
+                self.trigger.setTitle(item.text || item.value);
+                return true;
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.options.value = v;
+        this.trigger.setValue(v);
+        this._checkTitle();
+    },
+
+    getValue: function () {
+        return this.options.value || [];
+    },
+
+    populate: function (items) {
+        BI.SingleTreeTrigger.superclass.populate.apply(this, arguments);
+        this.trigger.populate(items);
+    }
+
+});
+
+$.shortcut("bi.single_tree_trigger", BI.SingleTreeTrigger);BI.HorizontalDashLine = BI.inherit(BI.Widget, {
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.HorizontalDashLine.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:"bi-svg-line-horizontal",
+            gap:5,
+            line:8,
+            stroke: "#009de3",
+            fill:"white",
+            height:3,
+            width:200
+        })
+    },
+
+    _init: function () {
+        BI.HorizontalDashLine.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        this.setMove()
+    },
+
+    setLength : function (w) {
+        if(w === this.options.width){
+            return;
+        }
+        BI.HorizontalDashLine.superclass.setWidth.apply(this, arguments);
+        var o = this.options;
+        this.setMove()
+    },
+
+
+    setMove:function() {
+        var o = this.options;
+        this.svg.clear();
+        this.svg.path(this._createPath(0)).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+    },
+
+    _createPath : function (startPos) {
+        var o = this.options;
+        var path ="";
+        for(var j = 0; j < o.height; j++) {
+            for(var i = startPos - o.line; i < o.width; i+= o.line) {
+                path +="M" + (i + j)+ ","+ j
+                path +="L" + (i + j + o.line) + "," + j
+                i+= o.gap
+            }
+        }
+        return path;
+    }
+
+})
+$.shortcut("bi.horizontal_dash_line", BI.HorizontalDashLine);BI.VerticalDashLine = BI.inherit(BI.Widget, {
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.VerticalDashLine.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:"bi-svg-line-vertical",
+            gap:5,
+            line:8,
+            stroke: "#009de3",
+            fill:"white",
+            height:200,
+            width:3
+        })
+    },
+
+    _init: function () {
+        BI.VerticalDashLine.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        this.setMove()
+    },
+
+    setLength : function (w) {
+        if(w === this.options.height){
+            return;
+        }
+        BI.VerticalDashLine.superclass.setHeight.apply(this, arguments);
+        this.setMove()
+    },
+
+
+    setMove:function() {
+        var o = this.options;
+        this.svg.clear();
+        this.svg.path(this._createPath(0)).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+    },
+
+    _createPath : function (startPos) {
+        var o = this.options;
+        var path ="";
+        for(var j = 0; j < o.width; j++) {
+            for(var i = startPos - o.line; i < o.height; i+= o.line) {
+                path +="M"+ j + "," + (i + j)
+                path +="L" + j + "," + (i + j + o.line)
+                i+= o.gap
+            }
+        }
+        return path;
+    }
+
+})
+$.shortcut("bi.vertical_dash_line", BI.VerticalDashLine);BI.TriangleDragButton = BI.inherit(BI.Widget, {
+    _defaultConfig: function() {
+        return BI.extend(BI.TriangleDragButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:  "bi-triangle-drag-button",
+            height : 30,
+            width : 30,
+            lineCount:6,
+            stroke: "#009de3",
+            fill:"white",
+            drag : null
+        })
+    },
+
+
+    _init : function() {
+        BI.TriangleDragButton.superclass._init.apply(this, arguments);
+        var o = this.options;
+        var svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        var path = "";
+        var h_step = o.height/ o.lineCount;
+        var w_step = o.width/ o.lineCount;
+        for(var i = 0; i < o.lineCount; i++){
+            path +="M0," +(h_step * (i + 1));
+            path +="L" + (w_step * (i + 1)) +",0"
+        }
+        svg.path(path).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+        this.reInitDrag();
+    },
+
+    reInitDrag : function () {
+        var o = this.options;
+        if(BI.isNotNull(o.drag)) {
+            this.element.draggable(o.drag)
+        }
+    }
+});
+
+$.shortcut("bi.triangle_drag_button", BI.TriangleDragButton);/**
+ * 可以交换列位置的表格
+ *
+ * @class BI.SortableTable
+ * @extends BI.Widget
+ */
+BI.SortableTable = BI.inherit(BI.Widget, {
+
+    _const: {
+        perColumnSize: 100,
+        dragButtonWidth: 24,
+        dragButtonHeight: 24,
+        lineCount: 6,
+        lineWidth: 3
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SortableTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sortable-table",
+
+            headerRowSize: 30,
+            footerRowSize: 25,
+            rowSize: 25,
+            sortable: true,
+
+            header: [],
+            items: [] //二维数组
+        });
+    },
+
+    _init: function () {
+        BI.SortableTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.insertLine = [];
+
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            isNeedResize: false,
+            isResizeAdapt: false,
+            columnSize: [],
+            headerRowSize: o.headerRowSize,
+            footerRowSize: o.footerRowSize,
+            rowSize: o.rowSize,
+            regionColumnSize: false,
+            header: o.header,
+            items: o.items
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            if(o.sortable === true){
+                self._initDrag();
+                self._createDashedLines();
+                self._createInsertLine();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            if(o.sortable === true){
+                self._createDashedLines();
+                self._createInsertLine();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments);
+        });
+
+        this.table.element.mousemove(function(e){
+            BI.each(self.dragHelpers, function(idx, dragHelper){
+                var visible = (idx === self._getMouseInColumnIndex(e));
+                dragHelper.setVisible(visible);
+                BI.each(self.dragHelpersLines[idx], function(id, line){
+                    line.setVisible(visible);
+                })
+            })
+        })
+
+        this.table.element.hover(function(e){
+        }, function(e){
+            BI.each(self.dragHelpers, function(idx, dragHelper){
+                dragHelper.setVisible(false);
+                BI.each(self.dragHelpersLines[idx], function(id, line){
+                    line.setVisible(false);
+                })
+            })
+        });
+
+        this.element.droppable({
+            accept: ".drag-header",
+            drop: function (e, ui) {
+                var absolutePosition = ui.position.left + self.table.getRightHorizontalScroll() + (e.pageX - ui.helper.offset().left);
+                var dropPosition = self._getColumnsLeftBorderDistance();
+                var insertIndex = self._getNearIndexFromArray(dropPosition, absolutePosition)
+                //这个insertIndex是包含原元素的index
+                //调整item顺序,重新populate
+                var flag = self._exchangeItemsAndHeaderPosition(ui.helper.data("index"), insertIndex)
+                if(flag === true){
+                    BI.nextTick(function(){
+                        self.populate(o.items, o.header);
+                    });
+                    self.fireEvent(BI.SortableTable.EVENT_CHANGE, ui.helper.data("index"), insertIndex);
+                }
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrollx: false,
+            element: this,
+            items: [this.table]
+        });
+    },
+
+    /**
+     * 插入到对应列的辅助线
+     * @private
+     */
+    _createInsertLine: function(){
+        var self = this;
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var height = this.table.getClientRegionRowSize()[0];
+        var lineObj = {
+            type: "bi.layout",
+            cls: "insert-help-line",
+            invisible: true
+        };
+        this.insertLine = [BI.createWidget(lineObj)];
+        var hearders = this.table.getColumns().header[0];
+        BI.each(hearders, function(idx, header){
+            var line = BI.createWidget(BI.extend(lineObj));
+            self.insertLine.push(line);
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.table.element,
+            items: BI.map(self.insertLine, function(idx, line){
+                if(idx === self.insertLine.length - 1){
+                    return {
+                        el: line,
+                        top: 0,
+                        height: height,
+                        right: 0
+                    }
+                }
+                return {
+                    el: line,
+                    top: 0,
+                    height: height,
+                    left: dropPosition[idx]
+                }
+            })
+        })
+    },
+
+    _createDashedLines: function(){
+        var self = this, c = this._const, o = this.options;
+        var RowsSize = this.table.getClientRegionRowSize();
+        var columnsSizes = this.table.getCalculateColumnSize();
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var len = this.table.getCalculateRegionColumnSize()[0];
+        this.dragHelpersLines = [];
+        BI.each(this.table.getColumns().header[0], function(idx, header){
+            self.dragHelpersLines.push([BI.createWidget({
+                type:"bi.horizontal_dash_line",      //上
+                width: columnsSizes[idx],
+                height: c.lineWidth,
+                invisible: true
+            }),BI.createWidget({
+                type:"bi.vertical_dash_line",        //右
+                width: c.lineWidth,
+                height: RowsSize[0],
+                invisible: true
+            }),BI.createWidget({
+                type:"bi.horizontal_dash_line",      //下
+                width: columnsSizes[idx],
+                height: c.lineWidth,
+                invisible: true
+            }),BI.createWidget({                //左
+                type:"bi.vertical_dash_line",
+                width: c.lineWidth,
+                height: RowsSize[0],
+                invisible: true
+            })]);
+        });
+        var length = this.dragHelpersLines.length;
+        BI.createWidget({
+            type: "bi.absolute",
+            element: self.table,
+            items: BI.flatten(BI.map(this.dragHelpersLines, function(idx, children){
+                return BI.map(children, function(id, child){
+                    var baseObj = {
+                        el: child,
+                        width: id % 2 === 0 ? columnsSizes[idx] : c.lineWidth,
+                        height: id % 2 === 0 ? c.lineWidth : RowsSize[0]
+                    }
+                    if(id === 0 || id === children.length - 1){     //上和左
+                        return BI.extend({
+                            top: 0,
+                            left: dropPosition[idx],
+                        }, baseObj)
+                    }else{
+                        return BI.extend({                                    //右和下
+                            bottom: 0,
+                            right:  idx === length - 1 ? 0 : len - dropPosition[idx + 1],
+                        }, baseObj)
+                    }
+                });
+            }))
+        })
+    },
+
+    _initDrag: function(){
+        var self = this, c = this._const, o = this.options;
+        this.dragHelpers = [];
+        BI.each(this.table.getColumns().header[0], function(idx, header){
+            var dragButton = BI.createWidget({
+                type: "bi.triangle_drag_button",
+                cls: "drag-header",
+                width: c.dragButtonWidth,
+                height: c.dragButtonHeight,
+                lineCount: c.lineCount,
+                invisible: true
+            });
+            BI.createWidget({
+                type: "bi.absolute",
+                element: header,
+                items: [{
+                    el: dragButton,
+                    top: 0,
+                    left: 0
+                }]
+            })
+
+            dragButton.element.draggable({
+                axis: "x",      //拖拽路径
+                revert: false,
+                cursor: BICst.cursorUrl,
+                cursorAt: {left: 5, top: 5},
+                containment: self.element,   //约束拖拽区域
+                drag: function(e, ui){
+                    self._showInsertHelpLine(e, ui);
+                },
+                stop: function(){
+                    BI.each(self.insertLine, function(idx, line){
+                        line.setVisible(false);
+                    })
+                },
+                helper: function () {
+                    var RowsSize = self.table.getClientRegionRowSize();
+                    var columnsSizes = self.table.getCalculateColumnSize();
+                    var clone = BI.createWidget({
+                        type: "bi.layout",
+                        cls: "sortable_table_drag_clone",
+                        data: {index: BI.parseInt(idx)},
+                        width: columnsSizes[idx],
+                        height: RowsSize[0]
+                    })
+                    clone.element.appendTo(self.element);
+                    return clone.element;
+                }
+            })
+            self.dragHelpers.push(dragButton);
+        });
+    },
+
+    _getMouseInColumnIndex: function(e){
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var columnsSizes = this.table.getCalculateColumnSize();
+        var tableHeight = this.table.getClientRegionRowSize()[0];
+        var tableOffsetLeft = e.pageX - this.table.element.offset().left;
+        var tableOffsetTop = this.table.element.offset().top;
+        return BI.find(BI.makeArray(dropPosition.length, null), function(idx){
+            return !(tableOffsetLeft < dropPosition[idx] || tableOffsetLeft > dropPosition[idx] + columnsSizes[idx]
+            || e.pageY < tableOffsetTop || e.pageY >= tableOffsetTop + tableHeight);
+        })
+    },
+
+    _getColumnsLeftBorderDistance: function(){
+        var dropPosition = [];
+        var columnSizes = this.table.getCalculateColumnSize();
+        BI.each(columnSizes, function(idx, columnSize){
+            if(idx === 0){
+                dropPosition.push(0)
+            }else{
+                //+ 1边框偏移值
+                dropPosition.push(dropPosition[idx - 1] + columnSizes[idx - 1] + 1)
+            }
+        });
+        return dropPosition;
+    },
+
+    _showInsertHelpLine: function(e, ui){
+        var absolutePosition =  ui.position.left + this.table.getRightHorizontalScroll() + (e.pageX - ui.helper.offset().left);
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var insertIndex = this._getNearIndexFromArray(dropPosition, absolutePosition);
+        BI.each(this.insertLine, function(idx, line){
+            line.setVisible(insertIndex === idx);
+        })
+        BI.each(this.dragHelpers, function(idx, helper){
+            helper.setVisible(false);
+        })
+    },
+
+    _exchangeItemsAndHeaderPosition: function (sourceIndex, targetIndex) {
+        var o = this.options;
+        if(sourceIndex === targetIndex){
+            return false;
+        }
+        var header = BI.unzip(o.header);
+        var items = BI.unzip(o.items);
+        var sourceHeader = header[sourceIndex];
+        var sourceitems = items[sourceIndex];
+        header.splice(targetIndex, 0, sourceHeader);
+        items.splice(targetIndex, 0, sourceitems);
+        var deleteIndex = (sourceIndex < targetIndex) ? sourceIndex : sourceIndex + 1;
+        BI.removeAt(header, deleteIndex);
+        BI.removeAt(items, deleteIndex);
+        o.header = BI.unzip(header);
+        o.items = BI.unzip(items);
+        return true;
+    },
+
+    _getNearIndexFromArray: function (array, v) {
+        var self = this;
+        var index = 0;
+        BI.some(array, function (idx, item) {
+            if (idx === array.length - 1) {
+                index = idx;
+                //如果是最后一列,且鼠标位置超出最后一列的中间位置,表示插入到最后
+                var len = self.table.getCalculateRegionColumnSize()[0];
+                var columnSizes = self.table.getCalculateColumnSize();
+                if(v > len - columnSizes[idx] / 2){
+                    index++;
+                }
+            } else {
+                if (v < array[idx + 1]) {
+                    var avg = (item + array[idx + 1]) / 2;
+
+                    index = v < avg ? idx : idx + 1;
+                    return true;
+                }
+            }
+        })
+        return index;
+    },
+
+    getColumns: function(){
+        return this.table.getColumns();
+    },
+
+    setSortable: function(sortable){
+        this.options.sortable = sortable;
+    },
+
+    populate: function (items, headers) {
+        var self = this, o = this.options;
+        o.header = headers;
+        o.items = items;
+        self.table.populate(o.items, o.header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.SortableTable.superclass.destroy.apply(this, arguments);
+    }
+});
+
+BI.SortableTable.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.sortable_table', BI.SortableTable);/**
+ * 可以单选多选切换的树
+ *
+ * Created by GUY on 2015/12/21.
+ * @class BI.SwitchTree
+ * @extends BI.Widget
+ */
+BI.SwitchTree = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SwitchTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-switch-tree",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SwitchTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tab = BI.createWidget({
+            type: "bi.tab",
+            element: this,
+            tab: null,
+            defaultShowIndex: BI.SwitchTree.SelectType.SingleSelect,
+            cardCreator: BI.bind(this._createTree, this)
+        });
+    },
+
+    _createTree: function (type) {
+        var self = this, o = this.options;
+        switch (type) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.levelTree = BI.createWidget({
+                    type: "bi.multilayer_single_level_tree",
+                    isDefaultInit: true,
+                    items: BI.deepClone(o.items)
+                });
+                this.levelTree.on(BI.LevelTree.EVENT_CHANGE, function () {
+                    self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments);
+                });
+                return this.levelTree;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.tree = BI.createWidget({
+                    type: "bi.simple_tree",
+                    items: this._removeIsParent(BI.deepClone(o.items))
+                });
+                this.tree.on(BI.SimpleTreeView.EVENT_CHANGE, function () {
+                    self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments);
+                });
+                return this.tree;
+        }
+    },
+
+    _removeIsParent: function(items) {
+        BI.each(items, function(i, item) {
+            BI.isNotNull(item.isParent) && delete item.isParent;
+        });
+        return items;
+    },
+
+    switchSelect: function () {
+        switch (this.getSelect()) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.setSelect(BI.SwitchTree.SelectType.MultiSelect);
+                break;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.setSelect(BI.SwitchTree.SelectType.SingleSelect);
+                break;
+        }
+    },
+
+    setSelect: function (v) {
+        this.tab.setSelect(v);
+    },
+
+    getSelect: function () {
+        return this.tab.getSelect();
+    },
+
+    setValue: function (v) {
+        this.storeValue = v;
+        switch (this.getSelect()) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.levelTree.setValue(v);
+                break;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.tree.setValue(v);
+                break;
+        }
+    },
+
+    getValue: function () {
+        return this.tab.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        if (BI.isNotNull(this.levelTree)) {
+            this.levelTree.populate(BI.deepClone(items));
+        }
+        if (BI.isNotNull(this.tree)) {
+            this.tree.populate(this._removeIsParent(BI.deepClone(items)));
+        }
+    }
+});
+BI.SwitchTree.EVENT_CHANGE = "SwitchTree.EVENT_CHANGE";
+BI.SwitchTree.SelectType = {
+    SingleSelect: BI.Selection.Single,
+    MultiSelect: BI.Selection.Multi
+};
+$.shortcut('bi.switch_tree', BI.SwitchTree);
+/**
+ * 文本组件中 编辑栏作为trigger
+ *
+ * Created by GameJian on 2016/1/24.
+ */
+BI.TextArea = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextArea.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-area"
+        });
+    },
+
+    _init: function () {
+        BI.TextArea.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.textarea = BI.createWidget({
+            type: "bi.textarea_editor",
+            width: "100%",
+            height: "100%"
+        });
+
+        this.textarea.on(BI.TextAreaEditor.EVENT_FOCUS, function () {
+            self.combo.showView();
+        });
+
+        this.textarea.on(BI.TextAreaEditor.EVENT_BLUR, function () {
+            if (BI.isEmptyString(this.getValue()) && !self.combo.isViewVisible()) {
+                self._showLabel();
+            } else {
+                self._showInput();
+            }
+            self.fireEvent(BI.TextArea.EVENT_VALUE_CHANGE, arguments)
+        });
+
+        this.toolbar = BI.createWidget({
+            type: "bi.text_toolbar"
+        });
+
+        this.toolbar.on(BI.TextToolbar.EVENT_CHANGE, function () {
+            var style = this.getValue();
+            self.textarea.setStyle(style);
+            self.element.css(style);
+            self.fireEvent(BI.TextArea.EVENT_VALUE_CHANGE, arguments);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            direction: "top",
+            isNeedAdjustWidth: false,
+            isNeedAdjustHeight: false,
+            adjustLength: 1,
+            el: this.textarea,
+            popup: {
+                el: this.toolbar,
+                width: 253,
+                height: 30,
+                stopPropagation: false
+            }
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            if (BI.isNotEmptyString(self.textarea.getValue())) {
+                self._showInput();
+            } else {
+                self._showLabel();
+            }
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.text_button",
+            cls: "text-area-editor-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-Click_To_Input_Text")
+        });
+
+        this.label.on(BI.TextButton.EVENT_CHANGE, function () {
+            self._showInput();
+            self.textarea.focus();
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 10,
+                right: 10,
+                top: 10,
+                bottom: 10
+            }, {
+                el: this.label,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    _showInput: function () {
+        this.label.setVisible(false);
+    },
+
+    _showLabel: function () {
+        this.label.setVisible(true);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        if (BI.isNotEmptyString(v.content)) {
+            this._showInput();
+        }
+        this.textarea.setValue(v.content);
+        this.toolbar.setValue(v.style);
+        this.textarea.setStyle(v.style);
+        this.element.css(v.style);
+    },
+
+    getValue: function () {
+        return {style: this.toolbar.getValue(), content: this.textarea.getValue()};
+    }
+});
+BI.TextArea.EVENT_VALUE_CHANGE = "EVENT_VALUE_CHANGE";
+$.shortcut("bi.text_area", BI.TextArea);/**
+ * 对齐方式选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarAlignChooser
+ * @extends BI.Widget
+ */
+BI.TextToolbarAlignChooser = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbarAlignChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar-align-chooser",
+            width: 60,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarAlignChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems([{
+                cls: "align-chooser-button text-align-left-font",
+                selected: true,
+                title: BI.i18nText("BI-Word_Align_Left"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_LEFT
+            }, {
+                cls: "align-chooser-button text-align-center-font",
+                title: BI.i18nText("BI-Word_Align_Middle"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_CENTER
+            }, {
+                cls: "align-chooser-button text-align-right-font",
+                title: BI.i18nText("BI-Word_Align_Right"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_RIGHT
+            }], {
+                type: "bi.icon_button",
+                height: o.height
+            }),
+            layouts: [{
+                type: "bi.center"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbarAlignChooser.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue()[0];
+    }
+});
+BI.extend(BI.TextToolbarAlignChooser, {
+    TEXT_ALIGN_LEFT: "left",
+    TEXT_ALIGN_CENTER: "center",
+    TEXT_ALIGN_RIGHT: "right"
+});
+BI.TextToolbarAlignChooser.EVENT_CHANGE = "BI.TextToolbarAlignChooser.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar_align_chooser', BI.TextToolbarAlignChooser);/**
+ * 颜色选择trigger
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarBackgroundChooserTrigger
+ * @extends BI.Widget
+ */
+BI.TextToolbarBackgroundChooserTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        var conf = BI.TextToolbarBackgroundChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-toolbar-background-chooser-trigger",
+            width: 20,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarBackgroundChooserTrigger.superclass._init.apply(this, arguments);
+        this.font = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-background-font"
+        });
+
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-underline-font"
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.font,
+                top: 3,
+                left: 2
+            }, {
+                el: this.underline,
+                top: 9,
+                left: 2
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.underline.element.css("color", color);
+    },
+
+    getValue: function () {
+        return this.font.element.css("color");
+    }
+});
+$.shortcut('bi.text_toolbar_background_chooser_trigger', BI.TextToolbarBackgroundChooserTrigger);/**
+ * 颜色选择trigger
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarColorChooserTrigger
+ * @extends BI.Widget
+ */
+BI.TextToolbarColorChooserTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        var conf = BI.TextToolbarColorChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-toolbar-color-chooser-trigger",
+            width: 20,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarColorChooserTrigger.superclass._init.apply(this, arguments);
+        this.font = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-font"
+        });
+
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-underline-font"
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.font,
+                top: 4,
+                left: 2
+            },{
+                el: this.underline,
+                top: 9,
+                left: 2
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.underline.element.css("color", color);
+    },
+
+    getValue: function () {
+        return this.font.element.css("color");
+    }
+});
+$.shortcut('bi.text_toolbar_color_chooser_trigger', BI.TextToolbarColorChooserTrigger);/**
+ * 字体大小选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarSizeChooser
+ * @extends BI.Widget
+ */
+BI.TextToolbarSizeChooser = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbarSizeChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar-size-chooser",
+            width: 50,
+            height: 20
+        });
+    },
+
+    _items: [{
+        value: 12
+    }, {
+        value: 14,
+        selected: true
+    }, {
+        value: 16
+    }, {
+        value: 18
+    }, {
+        value: 20
+    }, {
+        value: 22
+    }, {
+        value: 24
+    }, {
+        value: 26
+    }, {
+        value: 28
+    }, {
+        value: 30
+    }, {
+        value: 32
+    }, {
+        value: 34
+    }, {
+        value: 36
+    }, {
+        value: 38
+    }, {
+        value: 40
+    }, {
+        value: 64
+    }, {
+        value: 128
+    }],
+
+    _init: function () {
+        BI.TextToolbarSizeChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.editor_trigger",
+            cls: "text-toolbar-size-chooser-editor-trigger",
+            height: o.height,
+            triggerWidth: 12,
+            validationChecker: function (size) {
+                return BI.isInteger(size) && size > 0;
+            },
+            value: 14
+        });
+        this.trigger.on(BI.EditorTrigger.EVENT_CHANGE, function () {
+            self.setValue(BI.parseInt(this.getValue()));
+            self.fireEvent(BI.TextToolbarSizeChooser.EVENT_CHANGE, arguments);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: {
+                maxWidth: o.width,
+                minWidth: o.width,
+                el: {
+                    type: "bi.button_group",
+                    items: BI.createItems(this._items, {
+                        type: "bi.single_select_item"
+                    }),
+                    layouts: [{
+                        type: "bi.vertical"
+                    }]
+                }
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_CHANGE, function () {
+            this.hideView();
+            self.fireEvent(BI.TextToolbarSizeChooser.EVENT_CHANGE, arguments);
+        })
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+
+    getValue: function () {
+        return BI.parseInt(this.trigger.getValue());
+    }
+});
+BI.TextToolbarSizeChooser.EVENT_CHANGE = "BI.TextToolbarSizeChooser.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar_size_chooser', BI.TextToolbarSizeChooser);/**
+ * 颜色选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbar
+ * @extends BI.Widget
+ */
+BI.TextToolbar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbar.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar",
+            width: 253,
+            height: 28
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.size = BI.createWidget({
+            type: "bi.text_toolbar_size_chooser",
+            cls: "text-toolbar-size-chooser-trigger",
+            title: BI.i18nText("BI-Font_Size")
+        });
+        this.size.on(BI.TextToolbarSizeChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.bold = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Basic_Bold"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-bold-font"
+        });
+        this.bold.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.italic = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Basic_Italic"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-italic-font"
+        });
+        this.italic.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Underline"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-underline-font"
+        });
+        this.underline.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.colorchooser = BI.createWidget({
+            type: "bi.color_chooser",
+            el: {
+                type: "bi.text_toolbar_color_chooser_trigger",
+                title: BI.i18nText("BI-Font_Colour"),
+                cls: "text-toolbar-button"
+            }
+        });
+        this.colorchooser.on(BI.ColorChooser.EVENT_CHANGE, function () {
+
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.backgroundchooser = BI.createWidget({
+            type: "bi.color_chooser",
+            el: {
+                type: "bi.text_toolbar_background_chooser_trigger",
+                title: BI.i18nText("BI-Widget_Background_Colour"),
+                cls: "text-toolbar-button"
+            }
+        });
+        this.backgroundchooser.on(BI.ColorChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.alignchooser = BI.createWidget({
+            type: "bi.text_toolbar_align_chooser",
+            cls: "text-toolbar-button"
+        });
+        this.alignchooser.on(BI.TextToolbarAlignChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.size, this.bold, this.italic, this.underline, this.colorchooser, this.backgroundchooser, this.alignchooser],
+            hgap: 3,
+            vgap: 3
+        })
+    },
+
+    isColorChooserVisible: function () {
+        return this.colorchooser.isViewVisible();
+    },
+
+    isBackgroundChooserVisible: function () {
+        return this.backgroundchooser.isViewVisible();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.size.setValue(v["fontSize"] || 14);
+        this.bold.setSelected(v["fontWeight"] === "bold");
+        this.italic.setSelected(v["fontStyle"] === "italic");
+        this.underline.setSelected(v["textDecoration"] === "underline");
+        this.colorchooser.setValue(v["color"] || "#000000");
+        this.backgroundchooser.setValue(v["backgroundColor"] || "#ffffff");
+        this.alignchooser.setValue(v["textAlign"] || "left");
+    },
+
+    getValue: function () {
+        return {
+            "fontSize": this.size.getValue(),
+            "fontWeight": this.bold.isSelected() ? "bold" : "normal",
+            "fontStyle": this.italic.isSelected() ? "italic" : "normal",
+            "textDecoration": this.underline.isSelected() ? "underline" : "initial",
+            "color": this.colorchooser.getValue(),
+            "backgroundColor": this.backgroundchooser.getValue(),
+            "textAlign": this.alignchooser.getValue()
+        }
+    }
+});
+BI.TextToolbar.EVENT_CHANGE = "BI.TextToolbar.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar', BI.TextToolbar);/**
+ * Created by Baron on 2015/10/19.
+ */
+BI.TimeInterval = BI.inherit(BI.Single, {
+    constants: {
+        height: 25,
+        width: 25,
+        lgap: 15,
+        offset: -15,
+        timeErrorCls: "time-error",
+        DATE_MIN_VALUE: "1900-01-01",
+        DATE_MAX_VALUE: "2099-12-31"
+    },
+    _defaultConfig: function () {
+        var conf = BI.TimeInterval.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-time-interval"
+        })
+    },
+    _init: function () {
+        var self = this;
+        BI.TimeInterval.superclass._init.apply(this, arguments);
+
+        this.left = this._createCombo();
+        this.right = this._createCombo();
+        this.label = BI.createWidget({
+            type: 'bi.label',
+            height: this.constants.height,
+            width: this.constants.width,
+            text: "-"
+        });
+        BI.createWidget({
+            element: self,
+            type: "bi.center",
+            hgap: 15,
+            height: this.constants.height,
+            items: [{
+                type: "bi.absolute",
+                items: [{
+                    el: self.left,
+                    left: this.constants.offset,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: self.right,
+                    left: 0,
+                    right: this.constants.offset,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+        BI.createWidget({
+            type: "bi.horizontal_auto",
+            element: this,
+            items: [
+                self.label
+            ]
+        });
+    },
+
+    _createCombo: function () {
+        var self = this;
+        var combo = BI.createWidget({
+            type: 'bi.multidate_combo'
+        });
+        combo.on(BI.MultiDateCombo.EVENT_ERROR, function () {
+            self._clearTitle();
+            self.element.removeClass(self.constants.timeErrorCls);
+            self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_VALID, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+                    offsetStyle: "center"
+                });
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            } else {
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+            }
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_FOCUS, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+                    offsetStyle: "center"
+                });
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            } else {
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+            }
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.left.hidePopupView();
+            self.right.hidePopupView();
+        });
+        //combo.on(BI.MultiDateCombo.EVENT_CHANGE, function () {
+        //    BI.Bubbles.hide("error");
+        //    var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+        //    if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+        //        self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+        //        self.element.addClass(self.constants.timeErrorCls);
+        //        BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+        //            offsetStyle: "center"
+        //        });
+        //        self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+        //    } else {
+        //        self._clearTitle();
+        //        self.element.removeClass(self.constants.timeErrorCls);
+        //    }
+        //});
+
+        combo.on(BI.MultiDateCombo.EVENT_CONFIRM, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            }else{
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+                self.fireEvent(BI.TimeInterval.EVENT_CHANGE);
+            }
+        });
+        return combo;
+    },
+    _dateCheck: function (date) {
+        return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date;
+    },
+    _checkVoid: function (obj) {
+        return !Date.checkVoid(obj.year, obj.month, obj.day, this.constants.DATE_MIN_VALUE, this.constants.DATE_MAX_VALUE)[0];
+    },
+    _check: function (smallDate, bigDate) {
+        var smallObj = smallDate.match(/\d+/g), bigObj = bigDate.match(/\d+/g);
+        return this._dateCheck(smallDate) && Date.checkLegal(smallDate) && this._checkVoid({
+                year: smallObj[0],
+                month: smallObj[1],
+                day: smallObj[2]
+            }) && this._dateCheck(bigDate) && Date.checkLegal(bigDate) && this._checkVoid({
+                year: bigObj[0],
+                month: bigObj[1],
+                day: bigObj[2]
+            });
+    },
+    _compare: function (smallDate, bigDate) {
+        smallDate = Date.parseDateTime(smallDate, "%Y-%X-%d").print("%Y-%X-%d");
+        bigDate = Date.parseDateTime(bigDate, "%Y-%X-%d").print("%Y-%X-%d");
+        return BI.isNotNull(smallDate) && BI.isNotNull(bigDate) && smallDate > bigDate;
+    },
+    _setTitle: function (v) {
+        this.left.setTitle(v);
+        this.right.setTitle(v);
+        this.label.setTitle(v);
+    },
+    _clearTitle: function () {
+        this.left.setTitle("");
+        this.right.setTitle("");
+        this.label.setTitle("");
+    },
+    setValue: function (date) {
+        date = date || {};
+        this.left.setValue(date.start);
+        this.right.setValue(date.end);
+    },
+    getValue: function () {
+        return {start: this.left.getValue(), end: this.right.getValue()};
+    }
+});
+BI.TimeInterval.EVENT_VALID = "EVENT_VALID";
+BI.TimeInterval.EVENT_ERROR = "EVENT_ERROR";
+BI.TimeInterval.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.time_interval", BI.TimeInterval);/**
+ * Created by Young's on 2016/4/22.
+ */
+BI.DayTimeSetting = BI.inherit(BI.Widget, {
+    _defaultConfig: function(){
+        return BI.extend(BI.DayTimeSetting.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-time-setting-day",
+            day: 1
+        })
+    },
+
+    _init: function(){
+        BI.DayTimeSetting.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var decrease = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "-",
+            height: 28,
+            width: 28
+        });
+        decrease.on(BI.Button.EVENT_CHANGE, function(){
+            var day = BI.parseInt(self.day.getValue());
+            if(day === 1) {
+                day = 31;
+            } else {
+                day --;
+            }
+            self.day.setValue(day);
+            self.fireEvent(BI.DayTimeSetting.EVENT_CHANGE);
+        });
+
+        var increase = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "+",
+            height: 28,
+            width: 28
+        });
+        increase.on(BI.Button.EVENT_CHANGE, function(){
+            var day = BI.parseInt(self.day.getValue());
+            if(day === 31) {
+                day = 1;
+            } else {
+                day ++;
+            }
+            self.day.setValue(day);
+            self.fireEvent(BI.DayTimeSetting.EVENT_CHANGE);
+        });
+
+        this.day = BI.createWidget({
+            type: "bi.label",
+            value: o.day,
+            height: 30,
+            width: 40
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [decrease, this.day, increase, {
+                type: "bi.label",
+                text: BI.i18nText("BI-Day_Ri"),
+                height: 30,
+                width: 20
+            }],
+            height: 30
+        })
+    },
+
+    getValue: function(){
+        return BI.parseInt(this.day.getValue());
+    },
+
+    setValue: function(v) {
+        this.day.setValue(v);
+    }
+});
+BI.DayTimeSetting.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.day_time_setting", BI.DayTimeSetting);/**
+ * Created by Young's on 2016/4/22.
+ */
+BI.HourTimeSetting = BI.inherit(BI.Widget, {
+    _defaultConfig: function(){
+        return BI.extend(BI.HourTimeSetting.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-time-setting-hour",
+            hour: 0
+        })
+    },
+
+    _init: function(){
+        BI.HourTimeSetting.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var decrease = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "-",
+            height: 28,
+            width: 28
+        });
+        decrease.on(BI.Button.EVENT_CHANGE, function(){
+            var hour = BI.parseInt(self.hour.getValue());
+            if(hour === 0) {
+                hour = 23;
+            } else {
+                hour --;
+            }
+            self.hour.setValue(hour);
+            self.fireEvent(BI.HourTimeSetting.EVENT_CHANGE);
+        });
+
+        var increase = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "+",
+            height: 28,
+            width: 28
+        });
+        increase.on(BI.Button.EVENT_CHANGE, function(){
+            var hour = BI.parseInt(self.hour.getValue());
+            hour === 23 ? (hour = 0) : (hour ++);
+            self.hour.setValue(hour);
+            self.fireEvent(BI.HourTimeSetting.EVENT_CHANGE);
+        });
+
+        this.hour = BI.createWidget({
+            type: "bi.label",
+            value: o.hour,
+            height: 30,
+            width: 40
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [decrease, this.hour, increase, {
+                type: "bi.label",
+                text: BI.i18nText("BI-Hour_Dian"),
+                height: 30,
+                width: 20
+            }],
+            height: 30
+        })
+    },
+
+    getValue: function(){
+        return BI.parseInt(this.hour.getValue());
+    },
+
+    setValue: function(v) {
+        this.hour.setValue(v);
+    }
+});
+BI.HourTimeSetting.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.hour_time_setting", BI.HourTimeSetting);BI.TreeLabel = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TreeLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-label",
+            itemsCreator: BI.emptyFn,
+            titles: [],
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.TreeLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.titles = o.titles;
+        this.items = o.items;
+
+        this.view = BI.createWidget({
+            type: "bi.tree_label_view",
+            element: this,
+            titles: o.titles,
+            items: o.items
+        });
+        this.view.on(BI.TreeLabelView.EVENT_CHANGE, function (floors)  {
+            var op = {};
+            if (floors !== self.view.getMaxFloor() - 1) {
+                op.floors = floors;
+                op.selectedValues = self.getValue();
+                self._itemsCreator(op);
+            }
+            self.fireEvent(BI.TreeLabel.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _itemsCreator: function (options) {
+        var self = this, o = this.options;
+        o.itemsCreator(options, function (data) {
+            self.populate(data);
+        })
+    },
+
+    populate: function (v) {
+        this.view.populate(v);
+    },
+
+    getValue: function () {
+        return this.view.getValue();
+    }
+});
+BI.TreeLabel.EVENT_CHANGE = "BI.TreeLabel.EVENT_CHANGE";
+$.shortcut('bi.tree_label', BI.TreeLabel);BI.TreeLabelView = BI.inherit(BI.Widget, {
+    _constant: {
+        LIST_LABEL_HEIGHT: 40,
+        DEFAULT_LEFT_GAP: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.TreeLabelView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-label-view",
+            titleWidth: 60,
+            titles: [],
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.TreeLabelView.superclass._init.apply(this, arguments);
+        this.items = [];
+        this._initView();
+    },
+
+    _initView: function () {
+        var self = this, o = this.options;
+        this.title = BI.createWidget({
+            type: "bi.button_group",
+            height: this._constant.LIST_LABEL_HEIGHT * o.titles.length,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.right = BI.createWidget({
+            type: "bi.button_group",
+            cls: "list-label-group",
+            height: this._constant.LIST_LABEL_HEIGHT * this.items.length,
+            layouts: [{
+                type: "bi.horizontal"
+            }]
+        });
+        this._setTitles(o.titles);
+        this._setItems(o.items);
+        BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.title,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0,
+                width: 60
+            }, {
+                el: this.right,
+                left: 65,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }],
+            element: this
+        });
+    },
+
+    _setItems: function (items) {
+        var self = this;
+        var length = this.right.getAllButtons().length;
+        var deletes = [];
+        for (var i = 0; i < length; i++) {
+            deletes.push(i);
+        }
+        this.right.removeItemAt(deletes);
+        self.items = [];
+        BI.each(items, function (idx, values) {
+            var labelItems = [];
+            BI.each(values, function (idx, value) {
+                labelItems.push({
+                    title: value,
+                    text: value,
+                    value: value
+                })
+            });
+            var temp = BI.createWidget({
+                type: "bi.list_label",
+                items: labelItems,
+                showTitle: false
+            });
+            temp.on(BI.ListLabel.EVENT_CHANGE, function () {
+                self.fireEvent(BI.TreeLabelView.EVENT_CHANGE, idx);
+            });
+            self.items.push(temp);
+        });
+        var temp = BI.createWidget({
+            type: "bi.default",
+            items: self.items
+        });
+        this.right.addItems([temp]);
+        this.right.setHeight(self.items.length * this._constant.LIST_LABEL_HEIGHT);
+    },
+
+    _setTitles: function (titles) {
+        var length = this.title.getAllButtons().length;
+        var deletes = [], titleItems = [];
+        for (var i = 0; i < length; i++) {
+            deletes.push(i);
+        }
+        BI.each(titles, function (idx, title) {
+           titleItems.push({
+               text: title,
+               value: title,
+               title: title
+           });
+        });
+        this.title.removeItemAt(deletes);
+        this.title.addItems(BI.createItems(titleItems, {
+            type: "bi.label",
+            height: this._constant.LIST_LABEL_HEIGHT,
+            width: this.options.titleWidth
+        }));
+        this.title.setHeight(titles.length * this._constant.LIST_LABEL_HEIGHT);
+    },
+
+    _setValue: function (values) {
+        BI.each(this.items, function (idx, item) {
+            values[idx] && item.setValue(values[idx]);
+        })
+    },
+
+    populate: function(v) {
+        v.titles && this._setTitles(v.titles);
+        v.items && this._setItems(v.items);
+        v.values && this._setValue(v.values);
+    },
+
+    getMaxFloor: function () {
+        return this.items.length || 0;
+    },
+
+    getValue: function () {
+        var result = [];
+        BI.each(this.items, function (idx, item) {
+            result.push(item.getValue());
+        });
+        return result;
+    }
+});
+BI.TreeLabelView.EVENT_CHANGE = "BI.TreeLabelView.EVENT_CHANGE";
+$.shortcut('bi.tree_label_view', BI.TreeLabelView);/**
+ * Created by Young's on 2016/4/21.
+ */
+BI.UploadFileWithProgress = BI.inherit(BI.Widget, {
+
+    _constants: {
+        UPLOAD_PROGRESS: "__upload_progress__"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.UploadFileWithProgress.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-upload-file-with-progress",
+            progressEL: BICst.BODY_ELEMENT,
+            multiple: false,
+            maxSize: 1024 * 1024,
+            accept: "",
+            url: ""
+        })
+    },
+
+    _init: function () {
+        BI.UploadFileWithProgress.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.file = BI.createWidget({
+            type: "bi.multifile_editor",
+            width: "100%",
+            height: "100%",
+            name: o.name,
+            url: o.url,
+            multiple: o.multiple,
+            accept: o.accept,
+            maxSize: o.maxSize
+        });
+
+        this.file.on(BI.MultifileEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_CHANGE, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADSTART, function () {
+            self.progressBar = BI.createWidget({
+                type: "bi.progress_bar",
+                width: 300
+            });
+            BI.createWidget({
+                type: "bi.center_adapt",
+                element: BI.Layers.create(self._constants.UPLOAD_PROGRESS, self.options.progressEL),
+                items: [self.progressBar],
+                width: "100%",
+                height: "100%"
+            });
+
+            BI.Layers.show(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_UPLOADSTART, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_ERROR, function () {
+            BI.Layers.remove(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_ERROR, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_PROGRESS, function (data) {
+            var process = Math.ceil(data.loaded / data.total * 100);
+            self.progressBar.setValue(process > 100 ? 100 : process);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_PROGRESS, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADED, function () {
+            BI.Layers.remove(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_UPLOADED, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.adaptive",
+                    scrollable: false,
+                    items: [this.file]
+                },
+                top: 0,
+                right: 0,
+                left: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    select: function () {
+        this.file.select();
+    },
+
+    getValue: function () {
+        return this.file.getValue();
+    },
+
+    upload: function () {
+        this.file.upload();
+    },
+
+    reset: function () {
+        this.file.reset();
+    },
+
+    setEnable: function (enable) {
+        BI.MultiFile.superclass.setEnable.apply(this, arguments);
+        this.file.setEnable(enable);
+    }
+});
+BI.UploadFileWithProgress.EVENT_CHANGE = "EVENT_CHANGE";
+BI.UploadFileWithProgress.EVENT_UPLOADSTART = "EVENT_UPLOADSTART";
+BI.UploadFileWithProgress.EVENT_ERROR = "EVENT_ERROR";
+BI.UploadFileWithProgress.EVENT_PROGRESS = "EVENT_PROGRESS";
+BI.UploadFileWithProgress.EVENT_UPLOADED = "EVENT_UPLOADED";
+$.shortcut("bi.upload_file_with_progress", BI.UploadFileWithProgress);/**
+ * web组件
+ * Created by GameJian on 2016/3/1.
+ */
+BI.WebPage = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.WebPage.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-web-page"
+        })
+    },
+
+    _init: function () {
+        BI.WebPage.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.iframe = BI.createWidget({
+            type: "bi.iframe"
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.label",
+            cls: "web-page-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-Not_Add_Url")
+        });
+
+        this.del = BI.createWidget({
+            type: "bi.bubble_combo",
+            el: {
+                type: "bi.icon_button",
+                cls: "web-page-button img-shutdown-font",
+                title: BI.i18nText("BI-Basic_Delete"),
+                height: 24,
+                width: 24
+            },
+            popup: {
+                type: "bi.bubble_bar_popup_view",
+                buttons: [{
+                    value: BI.i18nText(BI.i18nText("BI-Basic_Sure")),
+                    handler: function () {
+                        self.fireEvent(BI.WebPage.EVENT_DESTROY)
+                    }
+                }, {
+                    value: BI.i18nText("BI-Basic_Cancel"),
+                    level: "ignore",
+                    handler: function () {
+                        self.del.hideView();
+                    }
+                }],
+                el: {
+                    type: "bi.vertical_adapt",
+                    items: [{
+                        type: "bi.label",
+                        text: BI.i18nText("BI-Sure_Delete_Current_Component"),
+                        cls: "web-page-delete-label",
+                        textAlign: "left",
+                        width: 300
+                    }],
+                    width: 300,
+                    height: 100,
+                    hgap: 20
+                },
+                maxHeight: 140,
+                minWidth: 340
+            },
+            invisible: true,
+            stopPropagation: true
+        });
+
+
+        this.href = BI.createWidget({
+            type: "bi.image_button_href",
+            cls: "web-page-button"
+        });
+
+        this.href.on(BI.ImageButtonHref.EVENT_CHANGE, function () {
+            var url = this.getValue();
+            self.setValue(this.getValue());
+            self._checkUrl(url);
+            self.fireEvent(BI.WebPage.EVENT_VALUE_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.iframe
+            }, {
+                el: this.del,
+                right: 4,
+                top: 8
+            }, {
+                el: this.href,
+                right: 36,
+                top: 8
+            }, {
+                el: this.label,
+                top: 32,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+
+        this.setToolbarVisible(false);
+        this._showLabel();
+    },
+
+    _checkUrl: function(url){
+        BI.Bubbles.hide(this.getName());
+        if(BI.isEmptyString(url)){
+            BI.Bubbles.show(this.getName(), BI.i18nText("BI-Click_To_Add_Hyperlink"), this.href, {
+                offsetStyle: "left"
+            });
+        }
+    },
+
+    _hideLabel: function () {
+        this.label.invisible()
+    },
+
+    isSelected: function () {
+        return this.href.isSelected();
+    },
+
+    _showLabel: function () {
+        this.label.visible()
+    },
+
+    setToolbarVisible: function (v) {
+        this.href.setVisible(v);
+        this.del.setVisible(v);
+    },
+
+    getValue: function () {
+        return this.href.getValue()
+    },
+
+    setValue: function (url) {
+        var self = this;
+        if (BI.isNotEmptyString(url)) {
+            self._hideLabel();
+        } else {
+            this.setToolbarVisible(true);
+            this.href.showView();
+        }
+        this.href.setValue(url);
+        this.iframe.setSrc(BI.Func.formatAddress(url))
+    }
+});
+
+BI.WebPage.EVENT_DESTROY = "EVENT_DESTROY";
+BI.WebPage.EVENT_VALUE_CHANGE = "EVENT_VALUE_CHANGE";
+$.shortcut("bi.web_page", BI.WebPage);/**
+ * 年份下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.YearCombo
+ * @extends BI.Widget
+ */
+BI.YearCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-combo",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.storeValue = "";
+        this.trigger = BI.createWidget({
+            type: "bi.year_trigger",
+            min: o.min,
+            max: o.max
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_START, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_STOP, function () {
+            self.combo.showView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_ERROR, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_CONFIRM, function () {
+            if(self.combo.isViewVisible()) {
+                return;
+            }
+            if (this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getKey());
+            } else if (!this.getKey()) {
+                self.setValue();
+            }
+            self.fireEvent(BI.YearCombo.EVENT_CONFIRM);
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.year_popup",
+            min: o.min,
+            max: o.max
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.YearCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            var value = self.trigger.getKey();
+            if (BI.isNotNull(value)) {
+                self.popup.setValue(value);
+            } else if(!value && value !== self.storeValue){
+                self.popup.setValue(self.storeValue);
+            }else {
+                self.setValue();
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+BI.YearCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_combo', BI.YearCombo);/**
+ * 年份展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.YearPopup
+ * @extends BI.Trigger
+ */
+BI.YearPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-popup",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31' //最大日期
+        });
+    },
+
+    _createYearCalendar: function (v) {
+        var o = this.options, y = this._year;
+
+        var calendar = BI.createWidget({
+            type: "bi.year_calendar",
+            min: o.min,
+            max: o.max,
+            logic: {
+                dynamic: true
+            },
+            year: y + v * 12
+        });
+        calendar.setValue(this._year);
+        return calendar;
+    },
+
+    _init: function () {
+        BI.YearPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        this.selectedYear = this._year = new Date().getFullYear();
+
+        var backBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-h-font",
+            width: 25,
+            height: 25,
+            value: -1
+        });
+
+        var preBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-h-font",
+            width: 25,
+            height: 25,
+            value: 1
+        });
+
+        this.navigation = BI.createWidget({
+            type: "bi.navigation",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            tab: {
+                cls: "year-popup-navigation",
+                height: 25,
+                items: [backBtn, preBtn]
+            },
+            cardCreator: BI.bind(this._createYearCalendar, this),
+
+            afterCardShow: function () {
+                this.setValue(self.selectedYear);
+                var calendar = this.getSelectedCard();
+                backBtn.setEnable(!calendar.isFrontYear());
+                preBtn.setEnable(!calendar.isFinalYear());
+            }
+        });
+
+        this.navigation.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedYear = this.getValue();
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            self.fireEvent(BI.YearPopup.EVENT_CHANGE, self.selectedYear);
+        });
+    },
+
+    getValue: function () {
+        return this.selectedYear;
+    },
+
+    setValue: function (v) {
+        var o = this.options;
+        if (Date.checkVoid(v, 1, 1, o.min, o.max)[0]) {
+            v = new Date().getFullYear();
+            this.selectedYear = "";
+            this.navigation.setSelect(BI.YearCalendar.getPageByYear(v));
+            this.navigation.setValue("");
+        } else {
+            this.selectedYear = v;
+            this.navigation.setSelect(BI.YearCalendar.getPageByYear(v));
+            this.navigation.setValue(v);
+        }
+    }
+});
+BI.YearPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.year_popup", BI.YearPopup);/**
+ * 年份trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.YearTrigger
+ * @extends BI.Trigger
+ */
+BI.YearTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 25,
+        errorText: BI.i18nText("BI-Please_Input_Integer"),
+        errorTextInvalid: BI.i18nText("BI-Year_Trigger_Invalid_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-year-trigger",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                self.editor.setErrorText(!BI.isPositiveInteger(v) ? c.errorText : c.errorTextInvalid);
+                return v === "" || (BI.isPositiveInteger(v) && !Date.checkVoid(v, 1, 1, o.min, o.max)[0]);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        })
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.YearTrigger.EVENT_CONFIRM);
+        })
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_ERROR);
+        });
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        baseCls: "bi-trigger-year-text",
+                        text: BI.i18nText("BI-Multi_Date_Year"),
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+    setValue: function (v) {
+        this.editor.setState(v);
+        this.editor.setValue(v);
+        this.editor.setTitle(v);
+    },
+    getKey: function () {
+        return this.editor.getValue() | 0;
+    }
+});
+BI.YearTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.YearTrigger.EVENT_ERROR = "EVENT_ERROR";
+BI.YearTrigger.EVENT_START = "EVENT_START";
+BI.YearTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.YearTrigger.EVENT_STOP = "EVENT_STOP";
+$.shortcut("bi.year_trigger", BI.YearTrigger);/**
+ * 年份 + 月份下拉框
+ *
+ * @class BI.YearMonthCombo
+ * @extends BI.Widget
+ */
+BI.YearMonthCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-month-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearMonthCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.year = BI.createWidget({
+            type: "bi.year_combo"
+        });
+
+        this.month = BI.createWidget({
+            type: "bi.month_combo"
+        });
+
+        this.year.on(BI.YearCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM);
+        });
+
+        this.month.on(BI.MonthCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM);
+        });
+
+        BI.createWidget({
+            type: "bi.center",
+            element: this,
+            hgap: 5,
+            items: [this.year, this.month]
+        });
+
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.month.setValue(v.month);
+        this.year.setValue(v.year);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            month: this.month.getValue()
+        };
+    }
+});
+BI.YearMonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_month_combo', BI.YearMonthCombo);/**
+ * 年份 + 月份下拉框
+ *
+ * @class BI.YearQuarterCombo
+ * @extends BI.Widget
+ */
+BI.YearQuarterCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearQuarterCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-quarter-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearQuarterCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.year = BI.createWidget({
+            type: "bi.year_combo"
+        });
+
+        this.quarter = BI.createWidget({
+            type: "bi.quarter_combo"
+        });
+
+        this.year.on(BI.YearCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM);
+        });
+
+        this.quarter.on(BI.QuarterCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM);
+        });
+
+        BI.createWidget({
+            type: "bi.center",
+            element: this,
+            hgap: 5,
+            items: [this.year, this.quarter]
+        });
+
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.quarter.setValue(v.quarter);
+        this.year.setValue(v.year);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            quarter: this.quarter.getValue()
+        };
+    }
+});
+BI.YearQuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_quarter_combo', BI.YearQuarterCombo);
\ No newline at end of file
diff --git a/src/css/base/single/text.css b/src/css/base/single/text.css
index 0128c7c7c..cf2c45754 100644
--- a/src/css/base/single/text.css
+++ b/src/css/base/single/text.css
@@ -5,5 +5,5 @@
   text-overflow: ellipsis;
   overflow-x: hidden;
   white-space: nowrap;
-  word-break: break-all;
+  word-break: break-word;
 }
diff --git a/src/css/base/third/jquery.mCustomScrollbar.css b/src/css/base/third/jquery.mCustomScrollbar.css
index 781f76cb5..b42acb6ec 100644
--- a/src/css/base/third/jquery.mCustomScrollbar.css
+++ b/src/css/base/third/jquery.mCustomScrollbar.css
@@ -384,7 +384,7 @@ yx-axis
 .mCSB_scrollTools .mCSB_buttonDown,
 .mCSB_scrollTools .mCSB_buttonLeft,
 .mCSB_scrollTools .mCSB_buttonRight {
-  background-image: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/mCSB_buttons.png');
+  background-image: url('background/mCSB_buttons.png');
   /* css sprites */
   background-repeat: no-repeat;
   opacity: 0.4;
diff --git a/src/css/base/third/ztree/zTreeStyle.css b/src/css/base/third/ztree/zTreeStyle.css
index ed435c0cf..2272c08b6 100644
--- a/src/css/base/third/ztree/zTreeStyle.css
+++ b/src/css/base/third/ztree/zTreeStyle.css
@@ -32,7 +32,7 @@ website:	http://code.google.com/p/jquerytree/
   padding: 0 0 0 18px;
 }
 .ztree li ul.line {
-  background: url(${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-1.png) 0 0 repeat-y;
+  background: url(icon/tree-vertical-line-1.png) 0 0 repeat-y;
 }
 .ztree li a {
   padding: 1px 3px 0 0;
@@ -98,31 +98,31 @@ website:	http://code.google.com/p/jquerytree/
   cursor: auto;
 }
 .ztree li span.button.chk.checkbox_false_full {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png");
+  background-image: url("icon/check-box-normal.png");
 }
 .ztree li span.button.chk.checkbox_false_full_focus {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png");
+  background-image: url("icon/check-box-normal.png");
 }
 .ztree li span.button.chk.checkbox_false_part {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image: url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_false_part_focus {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image: url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_false_disable {
   background-position: 0 -56px;
 }
 .ztree li span.button.chk.checkbox_true_full {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png");
+  background-image: url("icon/check-box-active.png");
 }
 .ztree li span.button.chk.checkbox_true_full_focus {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png");
+  background-image: url("icon/check-box-active.png");
 }
 .ztree li span.button.chk.checkbox_true_part {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image: url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_true_part_focus {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image: url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_true_disable {
   background-position: -14px -56px;
@@ -162,28 +162,28 @@ website:	http://code.google.com/p/jquerytree/
   height: 25px;
 }
 .ztree li span.button.root_open {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png");
+  background-image: url("icon/tree-expand-1.png");
 }
 .ztree li span.button.root_close {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png");
+  background-image: url("icon/tree-collapse-1.png");
 }
 .ztree li span.button.roots_open {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png");
+  background-image: url("icon/tree-expand-2.png");
 }
 .ztree li span.button.roots_close {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png");
+  background-image: url("icon/tree-collapse-2.png");
 }
 .ztree li span.button.center_open {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png");
+  background-image: url("icon/tree-expand-3.png");
 }
 .ztree li span.button.center_close {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png");
+  background-image: url("icon/tree-collapse-3.png");
 }
 .ztree li span.button.bottom_open {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png");
+  background-image: url("icon/tree-expand-4.png");
 }
 .ztree li span.button.bottom_close {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png");
+  background-image: url("icon/tree-collapse-4.png");
 }
 .ztree li span.button.noline_open {
   background-position: -92px -72px;
@@ -195,13 +195,13 @@ website:	http://code.google.com/p/jquerytree/
   background: none;
 }
 .ztree li span.button.roots_docu {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png");
+  background-image: url("icon/tree-vertical-line-2.png");
 }
 .ztree li span.button.center_docu {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png");
+  background-image: url("icon/tree-vertical-line-3.png");
 }
 .ztree li span.button.bottom_docu {
-  background-image: url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png");
+  background-image: url("icon/tree-vertical-line-4.png");
 }
 .ztree li span.button.noline_docu {
   background: none;
diff --git a/src/css/core/app.css b/src/css/core/app.css
index cc3812b8d..0ccd6dba8 100644
--- a/src/css/core/app.css
+++ b/src/css/core/app.css
@@ -3,7 +3,7 @@
 /**** custom color(自定义颜色,用于特定场景) ****/
 @font-face {
   font-family: 'bi';
-  src: url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.woff') format('woff'), /* chrome、firefox */ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('${servletURL}?op=resource&resource=/com/fr/bi/web/resources/fonts/iconfont.svg#svgFontName') format('svg');
+  src: url('font/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('font/iconfont.woff') format('woff'), /* chrome、firefox */ url('font/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('font/iconfont.svg#svgFontName') format('svg');
   
   /*  iOS 4.1- */
 }
diff --git a/src/css/normalize.css b/src/css/normalize.css
new file mode 100644
index 000000000..65b0635b2
--- /dev/null
+++ b/src/css/normalize.css
@@ -0,0 +1,230 @@
+/*! normalize.css v1.0.0 | MIT License | git.io/normalize */
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+video {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden] {
+  display: none;
+}
+html {
+  font-size: 100%;
+  -webkit-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%;
+}
+html,
+button,
+input,
+select,
+textarea {
+  font-family: sans-serif;
+}
+body {
+  margin: 0;
+}
+a:focus {
+  outline: thin dotted;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+h2 {
+  font-size: 1.5em;
+  margin: 0.83em 0;
+}
+h3 {
+  font-size: 1.17em;
+  margin: 1em 0;
+}
+h4 {
+  font-size: 1em;
+  margin: 1.33em 0;
+}
+h5 {
+  font-size: .83em;
+  margin: 1.67em 0;
+}
+h6 {
+  font-size: .75em;
+  margin: 2.33em 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+blockquote {
+  margin: 1em 40px;
+}
+dfn {
+  font-style: italic;
+}
+mark {
+  background: #ff0;
+  color: #000000;
+}
+p,
+pre {
+  margin: 1em 0;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, serif;
+  _font-family: 'courier new', monospace;
+  font-size: 1em;
+}
+pre {
+  white-space: pre;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+q {
+  quotes: none;
+}
+q:before,
+q:after {
+  content: '';
+  content: none;
+}
+small {
+  font-size: 75%;
+}
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+sup {
+  top: -0.5em;
+}
+sub {
+  bottom: -0.25em;
+}
+dl,
+menu,
+ol,
+ul {
+  margin: 1em 0;
+}
+dd {
+  margin: 0 0 0 40px;
+}
+menu,
+ol,
+ul {
+  padding: 0 0 0 40px;
+}
+nav ul,
+nav ol {
+  list-style: none;
+  list-style-image: none;
+}
+img {
+  border: 0;
+  -ms-interpolation-mode: bicubic;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 0;
+}
+form {
+  margin: 0;
+}
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+legend {
+  border: 0;
+  padding: 0;
+  white-space: normal;
+  *margin-left: -7px;
+}
+button,
+input,
+select,
+textarea {
+  font-size: 100%;
+  margin: 0;
+  vertical-align: baseline;
+  *vertical-align: middle;
+}
+button,
+input {
+  line-height: normal;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+  *overflow: visible;
+}
+button[disabled],
+input[disabled] {
+  cursor: default;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  padding: 0;
+  *height: 13px;
+  *width: 13px;
+}
+input[type="search"] {
+  -webkit-appearance: textfield;
+  -moz-box-sizing: content-box;
+  -webkit-box-sizing: content-box;
+  box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+textarea {
+  overflow: auto;
+  vertical-align: top;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
diff --git a/src/css/utils/background.css b/src/css/utils/background.css
index cc6bf5e1b..958ba6d1f 100644
--- a/src/css/utils/background.css
+++ b/src/css/utils/background.css
@@ -1,522 +1,522 @@
 .base-line-conn-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-1.png') repeat-y 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-1.png');
+  background: url('icon/tree-vertical-line-1.png') repeat-y 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-1.png');
   _background: none;
 }
 .first-line-conn-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png');
+  background: url('icon/tree-vertical-line-2.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
   _background: none;
 }
 .last-line-conn-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png');
+  background: url('icon/tree-vertical-line-4.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
   _background: none;
 }
 .mid-line-conn-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png');
+  background: url('icon/tree-vertical-line-3.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
   _background: none;
 }
 .loading-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading.gif') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading.gif');
+  background: url('icon/loading.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading.gif');
   _background: none;
 }
 .loading-background-f25 {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/F.25.gif') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/F.25.gif');
+  background: url('background/F.25.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/F.25.gif');
   _background: none;
 }
 .loading-background-e50 {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/E.50.gif') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/E.50.gif');
+  background: url('background/E.50.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/E.50.gif');
   _background: none;
 }
 .loading-background-d100 {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/D.100.gif') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/D.100.gif');
+  background: url('background/D.100.gif') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/D.100.gif');
   _background: none;
 }
 .axis-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis.png');
+  background: url('background/charts/axis.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-accu-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_accu.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_accu.png');
+  background: url('background/charts/axis_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_accu.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-percent-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_percent.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_percent.png');
+  background: url('background/charts/axis_percent.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_percent.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-compare-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_compare.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_compare.png');
+  background: url('background/charts/axis_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_compare.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-fall-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_fall.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/axis_fall.png');
+  background: url('background/charts/axis_fall.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/axis_fall.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bubble-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bubble.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bubble.png');
+  background: url('background/charts/bubble.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bubble.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bubble-force-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bubble_force.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bubble_force.png');
+  background: url('background/charts/bubble_force.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bubble_force.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .dashboard-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/dashboard.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/dashboard.png');
+  background: url('background/charts/dashboard.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/dashboard.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .donut-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/donut.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/donut.png');
+  background: url('background/charts/donut.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/donut.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .funnel-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/funnel.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/funnel.png');
+  background: url('background/charts/funnel.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/funnel.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map.png');
+  background: url('background/charts/map.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-gis-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_gis.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_gis.png');
+  background: url('background/charts/map_gis.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_gis.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg.png');
+  background: url('background/charts/map_svg.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-c-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg_c.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg_c.png');
+  background: url('background/charts/map_svg_c.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg_c.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-g-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg_g.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/map_svg_g.png');
+  background: url('background/charts/map_svg_g.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/map_svg_g.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .pie-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/pie.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/pie.png');
+  background: url('background/charts/pie.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/pie.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .radar-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/radar.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/radar.png');
+  background: url('background/charts/radar.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/radar.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .radar-accu-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/radar_accu.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/radar_accu.png');
+  background: url('background/charts/radar_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/radar_accu.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area.png');
+  background: url('background/charts/area.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-accu-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_accu.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_accu.png');
+  background: url('background/charts/area_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_accu.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-compare-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_compare.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_compare.png');
+  background: url('background/charts/area_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_compare.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-percent-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_percent.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_percent.png');
+  background: url('background/charts/area_percent.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_percent.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-range-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_range.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/area_range.png');
+  background: url('background/charts/area_range.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/area_range.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar.png');
+  background: url('background/charts/bar.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-accu-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar_accu.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar_accu.png');
+  background: url('background/charts/bar_accu.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar_accu.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-compare-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar_compare.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/bar_compare.png');
+  background: url('background/charts/bar_compare.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/bar_compare.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .combine-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/combine.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/combine.png');
+  background: url('background/charts/combine.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/combine.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .combine-m-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/combine_m.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/combine_m.png');
+  background: url('background/charts/combine_m.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/combine_m.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .line-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/line.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/line.png');
+  background: url('background/charts/line.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/line.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .scatter-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/scatter.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/scatter.png');
+  background: url('background/charts/scatter.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/scatter.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-complex-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_complex.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_complex.png');
+  background: url('background/charts/table_complex.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_complex.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-cross-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_cross.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_cross.png');
+  background: url('background/charts/table_cross.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_cross.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-group-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_group.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_group.png');
+  background: url('background/charts/table_group.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_group.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-detail-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_detail.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/table_detail.png');
+  background: url('background/charts/table_detail.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/table_detail.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_text.png');
+  background: url('background/charts/text/axis_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-accu-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_accu_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_accu_text.png');
+  background: url('background/charts/text/axis_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_accu_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-percent-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_percent_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_percent_text.png');
+  background: url('background/charts/text/axis_percent_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_percent_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-compare-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_compare_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_compare_text.png');
+  background: url('background/charts/text/axis_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_compare_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .axis-fall-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_fall_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/axis_fall_text.png');
+  background: url('background/charts/text/axis_fall_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/axis_fall_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bubble-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bubble_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bubble_text.png');
+  background: url('background/charts/text/bubble_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bubble_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bubble-force-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bubble_force_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bubble_force_text.png');
+  background: url('background/charts/text/bubble_force_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bubble_force_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .dashboard-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/dashboard_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/dashboard_text.png');
+  background: url('background/charts/text/dashboard_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/dashboard_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .donut-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/donut_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/donut_text.png');
+  background: url('background/charts/text/donut_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/donut_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .funnel-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/funnel_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/funnel_text.png');
+  background: url('background/charts/text/funnel_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/funnel_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_text.png');
+  background: url('background/charts/text/map_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-gis-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_gis_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_gis_text.png');
+  background: url('background/charts/text/map_gis_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_gis_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_text.png');
+  background: url('background/charts/text/map_svg_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-c-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_c_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_c_text.png');
+  background: url('background/charts/text/map_svg_c_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_c_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .map-svg-g-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_g_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/map_svg_g_text.png');
+  background: url('background/charts/text/map_svg_g_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/map_svg_g_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .pie-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/pie_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/pie_text.png');
+  background: url('background/charts/text/pie_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/pie_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .radar-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/radar_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/radar_text.png');
+  background: url('background/charts/text/radar_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/radar_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .radar-accu-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/radar_accu_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/radar_accu_text.png');
+  background: url('background/charts/text/radar_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/radar_accu_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_text.png');
+  background: url('background/charts/text/area_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-accu-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_accu_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_accu_text.png');
+  background: url('background/charts/text/area_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_accu_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-compare-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_compare_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_compare_text.png');
+  background: url('background/charts/text/area_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_compare_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-percent-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_percent_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_percent_text.png');
+  background: url('background/charts/text/area_percent_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_percent_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .area-range-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_range_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/area_range_text.png');
+  background: url('background/charts/text/area_range_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/area_range_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_text.png');
+  background: url('background/charts/text/bar_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-accu-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_accu_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_accu_text.png');
+  background: url('background/charts/text/bar_accu_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_accu_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .bar-compare-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_compare_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/bar_compare_text.png');
+  background: url('background/charts/text/bar_compare_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/bar_compare_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .combine-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/combine_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/combine_text.png');
+  background: url('background/charts/text/combine_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/combine_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .combine-m-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/combine_m_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/combine_m_text.png');
+  background: url('background/charts/text/combine_m_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/combine_m_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .line-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/line_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/line_text.png');
+  background: url('background/charts/text/line_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/line_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .scatter-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/text/scatter_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/text/scatter_text.png');
+  background: url('background/charts/text/text/scatter_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/text/scatter_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-complex-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_complex_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_complex_text.png');
+  background: url('background/charts/text/table_complex_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_complex_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-cross-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_cross_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_cross_text.png');
+  background: url('background/charts/text/table_cross_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_cross_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-group-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_group_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_group_text.png');
+  background: url('background/charts/text/table_group_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_group_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .table-detail-text-tip-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_detail_text.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/charts/text/table_detail_text.png');
+  background: url('background/charts/text/table_detail_text.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/charts/text/table_detail_text.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
 }
 .data-miss-background {
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/data_miss.png') no-repeat center center;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/background/data_miss.png');
+  background: url('background/data_miss.png') no-repeat center center;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background/data_miss.png');
   _background: none;
   background-color: #ffffff;
   z-index: 2;
diff --git a/src/css/utils/icon.css b/src/css/utils/icon.css
index c13c69563..002f421b8 100644
--- a/src/css/utils/icon.css
+++ b/src/css/utils/icon.css
@@ -2,2229 +2,2229 @@
 .tree-collapse-icon-type1:hover .x-icon,
 .tree-collapse-icon-type1:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png');
+  background: url('icon/tree-collapse-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-1.png');
   _background: none;
 }
 .tree-collapse-icon-type1.native .x-icon,
 .tree-collapse-icon-type1.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png');
+  background: url('icon/tree-collapse-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-1.png');
   _background: none;
 }
 .tree-collapse-icon-type2 .x-icon,
 .tree-collapse-icon-type2:hover .x-icon,
 .tree-collapse-icon-type2:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png');
+  background: url('icon/tree-collapse-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-2.png');
   _background: none;
 }
 .tree-collapse-icon-type2.native .x-icon,
 .tree-collapse-icon-type2.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png');
+  background: url('icon/tree-collapse-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-2.png');
   _background: none;
 }
 .tree-collapse-icon-type3 .x-icon,
 .tree-collapse-icon-type3:hover .x-icon,
 .tree-collapse-icon-type3:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png');
+  background: url('icon/tree-collapse-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-3.png');
   _background: none;
 }
 .tree-collapse-icon-type3.native .x-icon,
 .tree-collapse-icon-type3.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png');
+  background: url('icon/tree-collapse-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-3.png');
   _background: none;
 }
 .tree-collapse-icon-type4 .x-icon,
 .tree-collapse-icon-type4:hover .x-icon,
 .tree-collapse-icon-type4:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png');
+  background: url('icon/tree-collapse-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-4.png');
   _background: none;
 }
 .tree-collapse-icon-type4.native .x-icon,
 .tree-collapse-icon-type4.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png');
+  background: url('icon/tree-collapse-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-collapse-4.png');
   _background: none;
 }
 .tree-expand-icon-type1 .x-icon,
 .tree-expand-icon-type1:hover .x-icon,
 .tree-expand-icon-type1:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png');
+  background: url('icon/tree-expand-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-1.png');
   _background: none;
 }
 .tree-expand-icon-type1.native .x-icon,
 .tree-expand-icon-type1.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png');
+  background: url('icon/tree-expand-1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-1.png');
   _background: none;
 }
 .tree-expand-icon-type2 .x-icon,
 .tree-expand-icon-type2:hover .x-icon,
 .tree-expand-icon-type2:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png');
+  background: url('icon/tree-expand-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-2.png');
   _background: none;
 }
 .tree-expand-icon-type2.native .x-icon,
 .tree-expand-icon-type2.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png');
+  background: url('icon/tree-expand-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-2.png');
   _background: none;
 }
 .tree-expand-icon-type3 .x-icon,
 .tree-expand-icon-type3:hover .x-icon,
 .tree-expand-icon-type3:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png');
+  background: url('icon/tree-expand-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-3.png');
   _background: none;
 }
 .tree-expand-icon-type3.native .x-icon,
 .tree-expand-icon-type3.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png');
+  background: url('icon/tree-expand-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-3.png');
   _background: none;
 }
 .tree-expand-icon-type4 .x-icon,
 .tree-expand-icon-type4:hover .x-icon,
 .tree-expand-icon-type4:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png');
+  background: url('icon/tree-expand-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-4.png');
   _background: none;
 }
 .tree-expand-icon-type4.native .x-icon,
 .tree-expand-icon-type4.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png');
+  background: url('icon/tree-expand-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-expand-4.png');
   _background: none;
 }
 .tree-vertical-line-type2 .x-icon,
 .tree-vertical-line-type2:hover .x-icon,
 .tree-vertical-line-type2:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png');
+  background: url('icon/tree-vertical-line-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
   _background: none;
 }
 .tree-vertical-line-type2.native .x-icon,
 .tree-vertical-line-type2.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png');
+  background: url('icon/tree-vertical-line-2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-2.png');
   _background: none;
 }
 .tree-vertical-line-type3 .x-icon,
 .tree-vertical-line-type3:hover .x-icon,
 .tree-vertical-line-type3:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png');
+  background: url('icon/tree-vertical-line-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
   _background: none;
 }
 .tree-vertical-line-type3.native .x-icon,
 .tree-vertical-line-type3.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png');
+  background: url('icon/tree-vertical-line-3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-3.png');
   _background: none;
 }
 .tree-vertical-line-type4 .x-icon,
 .tree-vertical-line-type4:hover .x-icon,
 .tree-vertical-line-type4:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png');
+  background: url('icon/tree-vertical-line-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
   _background: none;
 }
 .tree-vertical-line-type4.native .x-icon,
 .tree-vertical-line-type4.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png');
+  background: url('icon/tree-vertical-line-4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/tree-vertical-line-4.png');
   _background: none;
 }
 .check-box-icon .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png');
+  background: url('icon/check-box-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-normal.png');
   _background: none;
 }
 .check-box-icon:hover .x-icon,
 .check-box-icon:focus .x-icon,
 .check-box-icon.hover .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png');
+  background: url('icon/check-box-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-normal.png');
   _background: none;
 }
 .check-box-icon:active .x-icon,
 .check-box-icon.active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png');
+  background: url('icon/check-box-active.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-active.png');
   _background: none;
 }
 .check-box-icon.native .x-icon,
 .check-box-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-disable.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-disable.png');
+  background: url('icon/check-box-disable.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-disable.png');
   _background: none;
 }
 .check-box-icon.native .x-icon,
 .check-box-icon.disabled.active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-disable2.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-disable2.png');
+  background: url('icon/check-box-disable2.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/check-box-disable2.png');
   _background: none;
 }
 .radio-icon .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-normal.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-normal.png');
+  background: url('icon/radio-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-normal.png');
   _background: none;
 }
 .radio-icon:hover .x-icon,
 .radio-icon:focus .x-icon,
 .radio-icon.hover .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-normal.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-normal.png');
+  background: url('icon/radio-normal.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-normal.png');
   _background: none;
 }
 .radio-icon:active .x-icon,
 .radio-icon.active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-active.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-active.png');
+  background: url('icon/radio-active.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-active.png');
   _background: none;
 }
 .radio-icon.native .x-icon,
 .radio-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-disable.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-disable.png');
+  background: url('icon/radio-disable.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-disable.png');
   _background: none;
 }
 .radio-icon.native .x-icon,
 .radio-icon.disabled.active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-disable2.png') no-repeat 0 0;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/radio-disable2.png');
+  background: url('icon/radio-disable2.png') no-repeat 0 0;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/radio-disable2.png');
   _background: none;
 }
 .check-half-select-icon .x-icon,
 .check-half-select-icon:hover .x-icon,
 .check-half-select-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png');
+  background: url('icon/half_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/half_selected.png');
   _background: none;
 }
 .check-half-select-icon.native .x-icon,
 .check-half-select-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png');
+  background: url('icon/half_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/half_selected.png');
   _background: none;
 }
 .loading-bar-icon .x-icon,
 .loading-bar-icon:hover .x-icon,
 .loading-bar-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading_bar.gif') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading_bar.gif');
+  background: url('icon/loading_bar.gif') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading_bar.gif');
   _background: none;
 }
 .loading-bar-icon.native .x-icon,
 .loading-bar-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading_bar.gif') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/loading_bar.gif');
+  background: url('icon/loading_bar.gif') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/loading_bar.gif');
   _background: none;
 }
 .left-join-icon .x-icon,
 .left-join-icon:hover .x-icon,
 .left-join-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/left-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/left-join.png');
+  background: url('icon/left-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/left-join.png');
   _background: none;
 }
 .left-join-icon.native .x-icon,
 .left-join-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/left-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/left-join.png');
+  background: url('icon/left-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/left-join.png');
   _background: none;
 }
 .right-join-icon .x-icon,
 .right-join-icon:hover .x-icon,
 .right-join-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/right-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/right-join.png');
+  background: url('icon/right-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/right-join.png');
   _background: none;
 }
 .right-join-icon.native .x-icon,
 .right-join-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/right-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/right-join.png');
+  background: url('icon/right-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/right-join.png');
   _background: none;
 }
 .inner-join-icon .x-icon,
 .inner-join-icon:hover .x-icon,
 .inner-join-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/inner-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/inner-join.png');
+  background: url('icon/inner-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/inner-join.png');
   _background: none;
 }
 .inner-join-icon.native .x-icon,
 .inner-join-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/inner-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/inner-join.png');
+  background: url('icon/inner-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/inner-join.png');
   _background: none;
 }
 .outer-join-icon .x-icon,
 .outer-join-icon:hover .x-icon,
 .outer-join-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/outer-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/outer-join.png');
+  background: url('icon/outer-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/outer-join.png');
   _background: none;
 }
 .outer-join-icon.native .x-icon,
 .outer-join-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/outer-join.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/outer-join.png');
+  background: url('icon/outer-join.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/outer-join.png');
   _background: none;
 }
 .data-link-test-fail-icon .x-icon,
 .data-link-test-fail-icon:hover .x-icon,
 .data-link-test-fail-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_fail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_fail.png');
+  background: url('icon/test_fail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_fail.png');
   _background: none;
 }
 .data-link-test-fail-icon.native .x-icon,
 .data-link-test-fail-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_fail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_fail.png');
+  background: url('icon/test_fail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_fail.png');
   _background: none;
 }
 .data-link-test-success-icon .x-icon,
 .data-link-test-success-icon:hover .x-icon,
 .data-link-test-success-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_success.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_success.png');
+  background: url('icon/test_success.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_success.png');
   _background: none;
 }
 .data-link-test-success-icon.native .x-icon,
 .data-link-test-success-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_success.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/test_success.png');
+  background: url('icon/test_success.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/test_success.png');
   _background: none;
 }
 .business-package-icon .x-icon,
 .business-package-icon:hover .x-icon,
 .business-package-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package.png');
+  background: url('icon/business_package.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package.png');
   _background: none;
 }
 .business-package-icon.native .x-icon,
 .business-package-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package.png');
+  background: url('icon/business_package.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package.png');
   _background: none;
 }
 .business-package-add-icon .x-icon,
 .business-package-add-icon:hover .x-icon,
 .business-package-add-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add.png');
+  background: url('icon/business_package_add.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add.png');
   _background: none;
 }
 .business-package-add-icon.native .x-icon,
 .business-package-add-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add.png');
+  background: url('icon/business_package_add.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add.png');
   _background: none;
 }
 .business-package-add-disable-icon .x-icon,
 .business-package-add-disable-icon:hover .x-icon,
 .business-package-add-disable-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add_disable.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add_disable.png');
+  background: url('icon/business_package_add_disable.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add_disable.png');
   _background: none;
 }
 .business-package-add-disable-icon.native .x-icon,
 .business-package-add-disable-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add_disable.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/business_package_add_disable.png');
+  background: url('icon/business_package_add_disable.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/business_package_add_disable.png');
   _background: none;
 }
 .business-package-selected-icon .x-icon,
 .business-package-selected-icon:hover .x-icon,
 .business-package-selected-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/package_selected.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/package_selected.png');
+  background: url('icon/package_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/package_selected.png');
   _background: none;
 }
 .business-package-selected-icon.native .x-icon,
 .business-package-selected-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/package_selected.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/package_selected.png');
+  background: url('icon/package_selected.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/package_selected.png');
   _background: none;
 }
 .card-view-report-icon .x-icon,
 .card-view-report-icon:hover .x-icon,
 .card-view-report-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/report.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/report.png');
+  background: url('icon/report.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/report.png');
   _background: none;
 }
 .card-view-report-icon.native .x-icon,
 .card-view-report-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/report.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/report.png');
+  background: url('icon/report.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/report.png');
   _background: none;
 }
 .card-view-real-time-icon .x-icon,
 .card-view-real-time-icon:hover .x-icon,
 .card-view-real-time-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/real_time.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/real_time.png');
+  background: url('icon/real_time.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/real_time.png');
   _background: none;
 }
 .card-view-real-time-icon.native .x-icon,
 .card-view-real-time-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/real_time.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/real_time.png');
+  background: url('icon/real_time.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/real_time.png');
   _background: none;
 }
 .table-style1-icon .x-icon,
 .table-style1-icon:hover .x-icon,
 .table-style1-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_1.png');
+  background: url('icon/table_style_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_1.png');
   _background: none;
 }
 .table-style1-icon.native .x-icon,
 .table-style1-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_1.png');
+  background: url('icon/table_style_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_1.png');
   _background: none;
 }
 .table-style2-icon .x-icon,
 .table-style2-icon:hover .x-icon,
 .table-style2-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_2.png');
+  background: url('icon/table_style_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_2.png');
   _background: none;
 }
 .table-style2-icon.native .x-icon,
 .table-style2-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_2.png');
+  background: url('icon/table_style_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_2.png');
   _background: none;
 }
 .table-style3-icon .x-icon,
 .table-style3-icon:hover .x-icon,
 .table-style3-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_3.png');
+  background: url('icon/table_style_3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_3.png');
   _background: none;
 }
 .table-style3-icon.native .x-icon,
 .table-style3-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_3.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/table_style_3.png');
+  background: url('icon/table_style_3.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/table_style_3.png');
   _background: none;
 }
 .axis-chart-style-gradual-icon .x-icon,
 .axis-chart-style-gradual-icon:hover .x-icon,
 .axis-chart-style-gradual-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_gradual.png');
+  background: url('icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_gradual.png');
   _background: none;
 }
 .axis-chart-style-gradual-icon.native .x-icon,
 .axis-chart-style-gradual-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_gradual.png');
+  background: url('icon/chartsetting/icon_style_gradual.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_gradual.png');
   _background: none;
 }
 .axis-chart-style-gradual-highlight-icon .x-icon,
 .axis-chart-style-gradual-highlight-icon:hover .x-icon,
 .axis-chart-style-gradual-highlight-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_gradual_highlight.png');
+  background: url('icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_gradual_highlight.png');
   _background: none;
 }
 .axis-chart-style-gradual-highlight-icon.native .x-icon,
 .axis-chart-style-gradual-highlight-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_gradual_highlight.png');
+  background: url('icon/chartsetting/icon_gradual_highlight.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_gradual_highlight.png');
   _background: none;
 }
 .axis-chart-style-normal-icon .x-icon,
 .axis-chart-style-normal-icon:hover .x-icon,
 .axis-chart-style-normal-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_normal.png');
+  background: url('icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_normal.png');
   _background: none;
 }
 .axis-chart-style-normal-icon.native .x-icon,
 .axis-chart-style-normal-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_normal.png');
+  background: url('icon/chartsetting/icon_style_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_normal.png');
   _background: none;
 }
 .axis-chart-style-transparent-icon .x-icon,
 .axis-chart-style-transparent-icon:hover .x-icon,
 .axis-chart-style-transparent-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_transparent.png');
+  background: url('icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_transparent.png');
   _background: none;
 }
 .axis-chart-style-transparent-icon.native .x-icon,
 .axis-chart-style-transparent-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_transparent.png');
+  background: url('icon/chartsetting/icon_style_transparent.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_transparent.png');
   _background: none;
 }
 .axis-chart-style-3d-icon .x-icon,
 .axis-chart-style-3d-icon:hover .x-icon,
 .axis-chart-style-3d-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_3d.png');
+  background: url('icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_3d.png');
   _background: none;
 }
 .axis-chart-style-3d-icon.native .x-icon,
 .axis-chart-style-3d-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_3d.png');
+  background: url('icon/chartsetting/icon_style_3d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_3d.png');
   _background: none;
 }
 .line-chart-style-curve-icon .x-icon,
 .line-chart-style-curve-icon:hover .x-icon,
 .line-chart-style-curve-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_curve.png');
+  background: url('icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_curve.png');
   _background: none;
 }
 .line-chart-style-curve-icon.native .x-icon,
 .line-chart-style-curve-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_curve.png');
+  background: url('icon/chartsetting/icon_style_line_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_curve.png');
   _background: none;
 }
 .line-chart-style-broken-icon .x-icon,
 .line-chart-style-broken-icon:hover .x-icon,
 .line-chart-style-broken-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_broken.png');
+  background: url('icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_broken.png');
   _background: none;
 }
 .line-chart-style-broken-icon.native .x-icon,
 .line-chart-style-broken-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_broken.png');
+  background: url('icon/chartsetting/icon_style_line_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_broken.png');
   _background: none;
 }
 .line-chart-style-vertical-icon .x-icon,
 .line-chart-style-vertical-icon:hover .x-icon,
 .line-chart-style-vertical-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_vertical.png');
+  background: url('icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_vertical.png');
   _background: none;
 }
 .line-chart-style-vertical-icon.native .x-icon,
 .line-chart-style-vertical-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_line_vertical.png');
+  background: url('icon/chartsetting/icon_style_line_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_line_vertical.png');
   _background: none;
 }
 .area-chart-style-curve-icon .x-icon,
 .area-chart-style-curve-icon:hover .x-icon,
 .area-chart-style-curve-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_curve.png');
+  background: url('icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_curve.png');
   _background: none;
 }
 .area-chart-style-curve-icon.native .x-icon,
 .area-chart-style-curve-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_curve.png');
+  background: url('icon/chartsetting/icon_style_area_curve.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_curve.png');
   _background: none;
 }
 .area-chart-style-broken-icon .x-icon,
 .area-chart-style-broken-icon:hover .x-icon,
 .area-chart-style-broken-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_broken.png');
+  background: url('icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_broken.png');
   _background: none;
 }
 .area-chart-style-broken-icon.native .x-icon,
 .area-chart-style-broken-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_broken.png');
+  background: url('icon/chartsetting/icon_style_area_broken.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_broken.png');
   _background: none;
 }
 .area-chart-style-vertical-icon .x-icon,
 .area-chart-style-vertical-icon:hover .x-icon,
 .area-chart-style-vertical-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_vertical.png');
+  background: url('icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_vertical.png');
   _background: none;
 }
 .area-chart-style-vertical-icon.native .x-icon,
 .area-chart-style-vertical-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_area_vertical.png');
+  background: url('icon/chartsetting/icon_style_area_vertical.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_area_vertical.png');
   _background: none;
 }
 .pie-chart-style-normal-icon .x-icon,
 .pie-chart-style-normal-icon:hover .x-icon,
 .pie-chart-style-normal-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_normal.png');
+  background: url('icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_normal.png');
   _background: none;
 }
 .pie-chart-style-normal-icon.native .x-icon,
 .pie-chart-style-normal-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_normal.png');
+  background: url('icon/chartsetting/icon_style_pie_normal.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_normal.png');
   _background: none;
 }
 .pie-chart-style-equal-arc-rose-icon .x-icon,
 .pie-chart-style-equal-arc-rose-icon:hover .x-icon,
 .pie-chart-style-equal-arc-rose-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_equal_arc_rose.png');
+  background: url('icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_equal_arc_rose.png');
   _background: none;
 }
 .pie-chart-style-equal-arc-rose-icon.native .x-icon,
 .pie-chart-style-equal-arc-rose-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_equal_arc_rose.png');
+  background: url('icon/chartsetting/icon_style_pie_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_equal_arc_rose.png');
   _background: none;
 }
 .pie-chart-style-not-equal-arc-rose-icon .x-icon,
 .pie-chart-style-not-equal-arc-rose-icon:hover .x-icon,
 .pie-chart-style-not-equal-arc-rose-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
+  background: url('icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
   _background: none;
 }
 .pie-chart-style-not-equal-arc-rose-icon.native .x-icon,
 .pie-chart-style-not-equal-arc-rose-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
+  background: url('icon/chartsetting/icon_style_pie_not_equal_arc_rose.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_pie_not_equal_arc_rose.png');
   _background: none;
 }
 .radar-chart-style-polygon-icon .x-icon,
 .radar-chart-style-polygon-icon:hover .x-icon,
 .radar-chart-style-polygon-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_polygon.png');
+  background: url('icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_polygon.png');
   _background: none;
 }
 .radar-chart-style-polygon-icon.native .x-icon,
 .radar-chart-style-polygon-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_polygon.png');
+  background: url('icon/chartsetting/icon_style_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_polygon.png');
   _background: none;
 }
 .acc_radar-chart-style-polygon-icon .x-icon,
 .acc_radar-chart-style-polygon-icon:hover .x-icon,
 .acc_radar-chart-style-polygon-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_polygon.png');
+  background: url('icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_polygon.png');
   _background: none;
 }
 .acc_radar-chart-style-polygon-icon.native .x-icon,
 .acc_radar-chart-style-polygon-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_polygon.png');
+  background: url('icon/chartsetting/icon_style_acc_radar_polygon.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_polygon.png');
   _background: none;
 }
 .acc_radar-chart-style-circle-icon .x-icon,
 .acc_radar-chart-style-circle-icon:hover .x-icon,
 .acc_radar-chart-style-circle-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_circle.png');
+  background: url('icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_circle.png');
   _background: none;
 }
 .acc_radar-chart-style-circle-icon.native .x-icon,
 .acc_radar-chart-style-circle-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_acc_radar_circle.png');
+  background: url('icon/chartsetting/icon_style_acc_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_acc_radar_circle.png');
   _background: none;
 }
 .radar-chart-style-circle-icon .x-icon,
 .radar-chart-style-circle-icon:hover .x-icon,
 .radar-chart-style-circle-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_circle.png');
+  background: url('icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_circle.png');
   _background: none;
 }
 .radar-chart-style-circle-icon.native .x-icon,
 .radar-chart-style-circle-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_style_radar_circle.png');
+  background: url('icon/chartsetting/icon_style_radar_circle.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_style_radar_circle.png');
   _background: none;
 }
 .dashboard-chart-style-360-icon .x-icon,
 .dashboard-chart-style-360-icon:hover .x-icon,
 .dashboard-chart-style-360-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_1.png');
+  background: url('icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_1.png');
   _background: none;
 }
 .dashboard-chart-style-360-icon.native .x-icon,
 .dashboard-chart-style-360-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_1.png');
+  background: url('icon/chartsetting/icon_dashboard_1.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_1.png');
   _background: none;
 }
 .dashboard-chart-style-180-icon .x-icon,
 .dashboard-chart-style-180-icon:hover .x-icon,
 .dashboard-chart-style-180-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_2.png');
+  background: url('icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_2.png');
   _background: none;
 }
 .dashboard-chart-style-180-icon.native .x-icon,
 .dashboard-chart-style-180-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_2.png');
+  background: url('icon/chartsetting/icon_dashboard_2.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_2.png');
   _background: none;
 }
 .dashboard-chart-style-percent-icon .x-icon,
 .dashboard-chart-style-percent-icon:hover .x-icon,
 .dashboard-chart-style-percent-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_4.png');
+  background: url('icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_4.png');
   _background: none;
 }
 .dashboard-chart-style-percent-icon.native .x-icon,
 .dashboard-chart-style-percent-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_4.png');
+  background: url('icon/chartsetting/icon_dashboard_4.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_4.png');
   _background: none;
 }
 .dashboard-chart-style-percent-scale-slot-icon .x-icon,
 .dashboard-chart-style-percent-scale-slot-icon:hover .x-icon,
 .dashboard-chart-style-percent-scale-slot-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_5.png');
+  background: url('icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_5.png');
   _background: none;
 }
 .dashboard-chart-style-percent-scale-slot-icon.native .x-icon,
 .dashboard-chart-style-percent-scale-slot-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_5.png');
+  background: url('icon/chartsetting/icon_dashboard_5.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_5.png');
   _background: none;
 }
 .dashboard-chart-style-vertical-tube-icon .x-icon,
 .dashboard-chart-style-vertical-tube-icon:hover .x-icon,
 .dashboard-chart-style-vertical-tube-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_6.png');
+  background: url('icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_6.png');
   _background: none;
 }
 .dashboard-chart-style-vertical-tube-icon.native .x-icon,
 .dashboard-chart-style-vertical-tube-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_6.png');
+  background: url('icon/chartsetting/icon_dashboard_6.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_6.png');
   _background: none;
 }
 .dashboard-chart-style-horizontal-tube-icon .x-icon,
 .dashboard-chart-style-horizontal-tube-icon:hover .x-icon,
 .dashboard-chart-style-horizontal-tube-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_7.png');
+  background: url('icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_7.png');
   _background: none;
 }
 .dashboard-chart-style-horizontal-tube-icon.native .x-icon,
 .dashboard-chart-style-horizontal-tube-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/chartsetting/icon_dashboard_7.png');
+  background: url('icon/chartsetting/icon_dashboard_7.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/chartsetting/icon_dashboard_7.png');
   _background: none;
 }
 .example-excel-icon .x-icon,
 .example-excel-icon:hover .x-icon,
 .example-excel-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/example.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/example.png');
+  background: url('icon/example.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/example.png');
   _background: none;
 }
 .example-excel-icon.native .x-icon,
 .example-excel-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/example.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/example.png');
+  background: url('icon/example.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/example.png');
   _background: none;
 }
 .dimension-no-data-icon .x-icon,
 .dimension-no-data-icon:hover .x-icon,
 .dimension-no-data-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png');
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
   _background: none;
 }
 .dimension-no-data-icon.native .x-icon,
 .dimension-no-data-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png');
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
   _background: none;
 }
 .drag-group-icon .x-icon,
 .drag-group-icon:hover .x-icon,
 .drag-group-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_group.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_group.png');
+  background: url('icon/drag/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_group.png');
   _background: none;
 }
 .drag-group-icon.native .x-icon,
 .drag-group-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_group.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_group.png');
+  background: url('icon/drag/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_group.png');
   _background: none;
 }
 .drag-cross-icon .x-icon,
 .drag-cross-icon:hover .x-icon,
 .drag-cross-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_cross.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_cross.png');
+  background: url('icon/drag/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_cross.png');
   _background: none;
 }
 .drag-cross-icon.native .x-icon,
 .drag-cross-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_cross.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_cross.png');
+  background: url('icon/drag/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_cross.png');
   _background: none;
 }
 .drag-complex-icon .x-icon,
 .drag-complex-icon:hover .x-icon,
 .drag-complex-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_complex.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_complex.png');
+  background: url('icon/drag/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_complex.png');
   _background: none;
 }
 .drag-complex-icon.native .x-icon,
 .drag-complex-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_complex.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_complex.png');
+  background: url('icon/drag/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_complex.png');
   _background: none;
 }
 .drag-axis-icon .x-icon,
 .drag-axis-icon:hover .x-icon,
 .drag-axis-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis.png');
+  background: url('icon/drag/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis.png');
   _background: none;
 }
 .drag-axis-icon.native .x-icon,
 .drag-axis-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis.png');
+  background: url('icon/drag/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis.png');
   _background: none;
 }
 .drag-axis-accu-icon .x-icon,
 .drag-axis-accu-icon:hover .x-icon,
 .drag-axis-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_a.png');
+  background: url('icon/drag/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_a.png');
   _background: none;
 }
 .drag-axis-accu-icon.native .x-icon,
 .drag-axis-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_a.png');
+  background: url('icon/drag/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_a.png');
   _background: none;
 }
 .drag-axis-percent-accu-icon .x-icon,
 .drag-axis-percent-accu-icon:hover .x-icon,
 .drag-axis-percent-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_pa.png');
+  background: url('icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_pa.png');
   _background: none;
 }
 .drag-axis-percent-accu-icon.native .x-icon,
 .drag-axis-percent-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_pa.png');
+  background: url('icon/drag/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_pa.png');
   _background: none;
 }
 .drag-axis-compare-icon .x-icon,
 .drag-axis-compare-icon:hover .x-icon,
 .drag-axis-compare-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_c.png');
+  background: url('icon/drag/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_c.png');
   _background: none;
 }
 .drag-axis-compare-icon.native .x-icon,
 .drag-axis-compare-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_c.png');
+  background: url('icon/drag/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_c.png');
   _background: none;
 }
 .drag-axis-fall-icon .x-icon,
 .drag-axis-fall-icon:hover .x-icon,
 .drag-axis-fall-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_f.png');
+  background: url('icon/drag/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_f.png');
   _background: none;
 }
 .drag-axis-fall-icon.native .x-icon,
 .drag-axis-fall-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_axis_f.png');
+  background: url('icon/drag/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_axis_f.png');
   _background: none;
 }
 .drag-bar-icon .x-icon,
 .drag-bar-icon:hover .x-icon,
 .drag-bar-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar.png');
+  background: url('icon/drag/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar.png');
   _background: none;
 }
 .drag-bar-icon.native .x-icon,
 .drag-bar-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar.png');
+  background: url('icon/drag/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar.png');
   _background: none;
 }
 .drag-bar-accu-icon .x-icon,
 .drag-bar-accu-icon:hover .x-icon,
 .drag-bar-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_a.png');
+  background: url('icon/drag/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_a.png');
   _background: none;
 }
 .drag-bar-accu-icon.native .x-icon,
 .drag-bar-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_a.png');
+  background: url('icon/drag/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_a.png');
   _background: none;
 }
 .drag-bar-compare-icon .x-icon,
 .drag-bar-compare-icon:hover .x-icon,
 .drag-bar-compare-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_c.png');
+  background: url('icon/drag/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_c.png');
   _background: none;
 }
 .drag-bar-compare-icon.native .x-icon,
 .drag-bar-compare-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bar_c.png');
+  background: url('icon/drag/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bar_c.png');
   _background: none;
 }
 .drag-area-icon .x-icon,
 .drag-area-icon:hover .x-icon,
 .drag-area-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area.png');
+  background: url('icon/drag/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area.png');
   _background: none;
 }
 .drag-area-icon.native .x-icon,
 .drag-area-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area.png');
+  background: url('icon/drag/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area.png');
   _background: none;
 }
 .drag-area-accu-icon .x-icon,
 .drag-area-accu-icon:hover .x-icon,
 .drag-area-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_a.png');
+  background: url('icon/drag/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_a.png');
   _background: none;
 }
 .drag-area-accu-icon.native .x-icon,
 .drag-area-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_a.png');
+  background: url('icon/drag/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_a.png');
   _background: none;
 }
 .drag-area-percent-accu-icon .x-icon,
 .drag-area-percent-accu-icon:hover .x-icon,
 .drag-area-percent-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_pa.png');
+  background: url('icon/drag/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_pa.png');
   _background: none;
 }
 .drag-area-percent-accu-icon.native .x-icon,
 .drag-area-percent-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_pa.png');
+  background: url('icon/drag/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_pa.png');
   _background: none;
 }
 .drag-area-compare-icon .x-icon,
 .drag-area-compare-icon:hover .x-icon,
 .drag-area-compare-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_c.png');
+  background: url('icon/drag/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_c.png');
   _background: none;
 }
 .drag-area-compare-icon.native .x-icon,
 .drag-area-compare-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_c.png');
+  background: url('icon/drag/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_c.png');
   _background: none;
 }
 .drag-area-range-icon .x-icon,
 .drag-area-range-icon:hover .x-icon,
 .drag-area-range-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_r.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_r.png');
+  background: url('icon/drag/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_r.png');
   _background: none;
 }
 .drag-area-range-icon.native .x-icon,
 .drag-area-range-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_r.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_area_r.png');
+  background: url('icon/drag/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_area_r.png');
   _background: none;
 }
 .drag-combine-icon .x-icon,
 .drag-combine-icon:hover .x-icon,
 .drag-combine-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine.png');
+  background: url('icon/drag/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine.png');
   _background: none;
 }
 .drag-combine-icon.native .x-icon,
 .drag-combine-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine.png');
+  background: url('icon/drag/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine.png');
   _background: none;
 }
 .drag-combine-mult-icon .x-icon,
 .drag-combine-mult-icon:hover .x-icon,
 .drag-combine-mult-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine_m.png');
+  background: url('icon/drag/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine_m.png');
   _background: none;
 }
 .drag-combine-mult-icon.native .x-icon,
 .drag-combine-mult-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_combine_m.png');
+  background: url('icon/drag/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_combine_m.png');
   _background: none;
 }
 .drag-line-icon .x-icon,
 .drag-line-icon:hover .x-icon,
 .drag-line-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_line.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_line.png');
+  background: url('icon/drag/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_line.png');
   _background: none;
 }
 .drag-line-icon.native .x-icon,
 .drag-line-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_line.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_line.png');
+  background: url('icon/drag/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_line.png');
   _background: none;
 }
 .drag-pie-icon .x-icon,
 .drag-pie-icon:hover .x-icon,
 .drag-pie-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_pie.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_pie.png');
+  background: url('icon/drag/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_pie.png');
   _background: none;
 }
 .drag-pie-icon.native .x-icon,
 .drag-pie-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_pie.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_pie.png');
+  background: url('icon/drag/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_pie.png');
   _background: none;
 }
 .drag-map-china-icon .x-icon,
 .drag-map-china-icon:hover .x-icon,
 .drag-map-china-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_c.png');
+  background: url('icon/drag/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_c.png');
   _background: none;
 }
 .drag-map-china-icon.native .x-icon,
 .drag-map-china-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_c.png');
+  background: url('icon/drag/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_c.png');
   _background: none;
 }
 .drag-map-global-icon .x-icon,
 .drag-map-global-icon:hover .x-icon,
 .drag-map-global-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_g.png');
+  background: url('icon/drag/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_g.png');
   _background: none;
 }
 .drag-map-global-icon.native .x-icon,
 .drag-map-global-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_g.png');
+  background: url('icon/drag/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_g.png');
   _background: none;
 }
 .drag-map-svg-icon .x-icon,
 .drag-map-svg-icon:hover .x-icon,
 .drag-map-svg-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_s.png');
+  background: url('icon/drag/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_s.png');
   _background: none;
 }
 .drag-map-svg-icon.native .x-icon,
 .drag-map-svg-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_s.png');
+  background: url('icon/drag/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_s.png');
   _background: none;
 }
 .drag-map-gis-icon .x-icon,
 .drag-map-gis-icon:hover .x-icon,
 .drag-map-gis-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_gis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_gis.png');
+  background: url('icon/drag/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_gis.png');
   _background: none;
 }
 .drag-map-gis-icon.native .x-icon,
 .drag-map-gis-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_gis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_map_gis.png');
+  background: url('icon/drag/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_map_gis.png');
   _background: none;
 }
 .drag-dashboard-icon .x-icon,
 .drag-dashboard-icon:hover .x-icon,
 .drag-dashboard-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_dashboard.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_dashboard.png');
+  background: url('icon/drag/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_dashboard.png');
   _background: none;
 }
 .drag-dashboard-icon.native .x-icon,
 .drag-dashboard-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_dashboard.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_dashboard.png');
+  background: url('icon/drag/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_dashboard.png');
   _background: none;
 }
 .drag-donut-icon .x-icon,
 .drag-donut-icon:hover .x-icon,
 .drag-donut-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_donut.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_donut.png');
+  background: url('icon/drag/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_donut.png');
   _background: none;
 }
 .drag-donut-icon.native .x-icon,
 .drag-donut-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_donut.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_donut.png');
+  background: url('icon/drag/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_donut.png');
   _background: none;
 }
 .drag-radar-icon .x-icon,
 .drag-radar-icon:hover .x-icon,
 .drag-radar-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar.png');
+  background: url('icon/drag/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar.png');
   _background: none;
 }
 .drag-radar-icon.native .x-icon,
 .drag-radar-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar.png');
+  background: url('icon/drag/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar.png');
   _background: none;
 }
 .drag-radar-accu-icon .x-icon,
 .drag-radar-accu-icon:hover .x-icon,
 .drag-radar-accu-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar_a.png');
+  background: url('icon/drag/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar_a.png');
   _background: none;
 }
 .drag-radar-accu-icon.native .x-icon,
 .drag-radar-accu-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_radar_a.png');
+  background: url('icon/drag/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_radar_a.png');
   _background: none;
 }
 .drag-bubble-icon .x-icon,
 .drag-bubble-icon:hover .x-icon,
 .drag-bubble-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble.png');
+  background: url('icon/drag/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble.png');
   _background: none;
 }
 .drag-bubble-icon.native .x-icon,
 .drag-bubble-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble.png');
+  background: url('icon/drag/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble.png');
   _background: none;
 }
 .drag-bubble-force-icon .x-icon,
 .drag-bubble-force-icon:hover .x-icon,
 .drag-bubble-force-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble_f.png');
+  background: url('icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble_f.png');
   _background: none;
 }
 .drag-bubble-force-icon.native .x-icon,
 .drag-bubble-force-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_bubble_f.png');
+  background: url('icon/drag/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_bubble_f.png');
   _background: none;
 }
 .drag-scatter-icon .x-icon,
 .drag-scatter-icon:hover .x-icon,
 .drag-scatter-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_scatter.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_scatter.png');
+  background: url('icon/drag/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_scatter.png');
   _background: none;
 }
 .drag-scatter-icon.native .x-icon,
 .drag-scatter-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_scatter.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_scatter.png');
+  background: url('icon/drag/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_scatter.png');
   _background: none;
 }
 .drag-funnel-icon .x-icon,
 .drag-funnel-icon:hover .x-icon,
 .drag-funnel-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_funnel.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_funnel.png');
+  background: url('icon/drag/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_funnel.png');
   _background: none;
 }
 .drag-funnel-icon.native .x-icon,
 .drag-funnel-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_funnel.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/icon_funnel.png');
+  background: url('icon/drag/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/icon_funnel.png');
   _background: none;
 }
 .drag-detail-icon .x-icon,
 .drag-detail-icon:hover .x-icon,
 .drag-detail-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_detail.png');
+  background: url('icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_detail.png');
   _background: none;
 }
 .drag-detail-icon.native .x-icon,
 .drag-detail-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_detail.png');
+  background: url('icon/drag/pure/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_detail.png');
   _background: none;
 }
 .drag-input-icon .x-icon,
 .drag-input-icon:hover .x-icon,
 .drag-input-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_input.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_input.png');
+  background: url('icon/drag/pure/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_input.png');
   _background: none;
 }
 .drag-input-icon.native .x-icon,
 .drag-input-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_input.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_input.png');
+  background: url('icon/drag/pure/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_input.png');
   _background: none;
 }
 .drag-web-icon .x-icon,
 .drag-web-icon:hover .x-icon,
 .drag-web-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_web.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_web.png');
+  background: url('icon/drag/pure/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_web.png');
   _background: none;
 }
 .drag-web-icon.native .x-icon,
 .drag-web-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_web.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_web.png');
+  background: url('icon/drag/pure/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_web.png');
   _background: none;
 }
 .drag-image-icon .x-icon,
 .drag-image-icon:hover .x-icon,
 .drag-image-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_image.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_image.png');
+  background: url('icon/drag/pure/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_image.png');
   _background: none;
 }
 .drag-image-icon.native .x-icon,
 .drag-image-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_image.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_image.png');
+  background: url('icon/drag/pure/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_image.png');
   _background: none;
 }
 .drag-string-icon .x-icon,
 .drag-string-icon:hover .x-icon,
 .drag-string-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_string.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_string.png');
+  background: url('icon/drag/pure/icon_string.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_string.png');
   _background: none;
 }
 .drag-string-icon.native .x-icon,
 .drag-string-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_string.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_string.png');
+  background: url('icon/drag/pure/icon_string.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_string.png');
   _background: none;
 }
 .drag-number-icon .x-icon,
 .drag-number-icon:hover .x-icon,
 .drag-number-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_number.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_number.png');
+  background: url('icon/drag/pure/icon_number.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_number.png');
   _background: none;
 }
 .drag-number-icon.native .x-icon,
 .drag-number-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_number.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_number.png');
+  background: url('icon/drag/pure/icon_number.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_number.png');
   _background: none;
 }
 .drag-tree-icon .x-icon,
 .drag-tree-icon:hover .x-icon,
 .drag-tree-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_tree.png');
+  background: url('icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_tree.png');
   _background: none;
 }
 .drag-tree-icon.native .x-icon,
 .drag-tree-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_tree.png');
+  background: url('icon/drag/pure/icon_tree.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_tree.png');
   _background: none;
 }
 .drag-date-icon .x-icon,
 .drag-date-icon:hover .x-icon,
 .drag-date-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_date.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_date.png');
+  background: url('icon/drag/pure/icon_date.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_date.png');
   _background: none;
 }
 .drag-date-icon.native .x-icon,
 .drag-date-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_date.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_date.png');
+  background: url('icon/drag/pure/icon_date.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_date.png');
   _background: none;
 }
 .drag-year-icon .x-icon,
 .drag-year-icon:hover .x-icon,
 .drag-year-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year.png');
+  background: url('icon/drag/pure/icon_year.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year.png');
   _background: none;
 }
 .drag-year-icon.native .x-icon,
 .drag-year-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year.png');
+  background: url('icon/drag/pure/icon_year.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year.png');
   _background: none;
 }
 .drag-year-month-icon .x-icon,
 .drag-year-month-icon:hover .x-icon,
 .drag-year-month-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m.png');
+  background: url('icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m.png');
   _background: none;
 }
 .drag-year-month-icon.native .x-icon,
 .drag-year-month-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m.png');
+  background: url('icon/drag/pure/icon_year_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m.png');
   _background: none;
 }
 .drag-year-season-icon .x-icon,
 .drag-year-season-icon:hover .x-icon,
 .drag-year-season-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_s.png');
+  background: url('icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_s.png');
   _background: none;
 }
 .drag-year-season-icon.native .x-icon,
 .drag-year-season-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_s.png');
+  background: url('icon/drag/pure/icon_year_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_s.png');
   _background: none;
 }
 .drag-ymd-icon .x-icon,
 .drag-ymd-icon:hover .x-icon,
 .drag-ymd-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m_d.png');
+  background: url('icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m_d.png');
   _background: none;
 }
 .drag-ymd-icon.native .x-icon,
 .drag-ymd-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_year_m_d.png');
+  background: url('icon/drag/pure/icon_year_m_d.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_year_m_d.png');
   _background: none;
 }
 .drag-general-query-icon .x-icon,
 .drag-general-query-icon:hover .x-icon,
 .drag-general-query-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query_g.png');
+  background: url('icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query_g.png');
   _background: none;
 }
 .drag-general-query-icon.native .x-icon,
 .drag-general-query-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query_g.png');
+  background: url('icon/drag/pure/icon_query_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query_g.png');
   _background: none;
 }
 .drag-query-icon .x-icon,
 .drag-query-icon:hover .x-icon,
 .drag-query-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query.png');
+  background: url('icon/drag/pure/icon_query.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query.png');
   _background: none;
 }
 .drag-query-icon.native .x-icon,
 .drag-query-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_query.png');
+  background: url('icon/drag/pure/icon_query.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_query.png');
   _background: none;
 }
 .drag-reset-icon .x-icon,
 .drag-reset-icon:hover .x-icon,
 .drag-reset-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reset.png');
+  background: url('icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reset.png');
   _background: none;
 }
 .drag-reset-icon.native .x-icon,
 .drag-reset-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reset.png');
+  background: url('icon/drag/pure/icon_reset.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reset.png');
   _background: none;
 }
 .drag-reuse-icon .x-icon,
 .drag-reuse-icon:hover .x-icon,
 .drag-reuse-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reuse.png');
+  background: url('icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reuse.png');
   _background: none;
 }
 .drag-reuse-icon.native .x-icon,
 .drag-reuse-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/pure/icon_reuse.png');
+  background: url('icon/drag/pure/icon_reuse.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/pure/icon_reuse.png');
   _background: none;
 }
 .drag-group-small-icon .x-icon,
 .drag-group-small-icon:hover .x-icon,
 .drag-group-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_group.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_group.png');
+  background: url('icon/drag/small/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_group.png');
   _background: none;
 }
 .drag-group-small-icon.native .x-icon,
 .drag-group-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_group.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_group.png');
+  background: url('icon/drag/small/icon_group.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_group.png');
   _background: none;
 }
 .drag-cross-small-icon .x-icon,
 .drag-cross-small-icon:hover .x-icon,
 .drag-cross-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_cross.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_cross.png');
+  background: url('icon/drag/small/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_cross.png');
   _background: none;
 }
 .drag-cross-small-icon.native .x-icon,
 .drag-cross-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_cross.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_cross.png');
+  background: url('icon/drag/small/icon_cross.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_cross.png');
   _background: none;
 }
 .drag-complex-small-icon .x-icon,
 .drag-complex-small-icon:hover .x-icon,
 .drag-complex-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_complex.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_complex.png');
+  background: url('icon/drag/small/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_complex.png');
   _background: none;
 }
 .drag-complex-small-icon.native .x-icon,
 .drag-complex-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_complex.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_complex.png');
+  background: url('icon/drag/small/icon_complex.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_complex.png');
   _background: none;
 }
 .drag-axis-small-icon .x-icon,
 .drag-axis-small-icon:hover .x-icon,
 .drag-axis-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis.png');
+  background: url('icon/drag/small/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis.png');
   _background: none;
 }
 .drag-axis-small-icon.native .x-icon,
 .drag-axis-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis.png');
+  background: url('icon/drag/small/icon_axis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis.png');
   _background: none;
 }
 .drag-axis-accu-small-icon .x-icon,
 .drag-axis-accu-small-icon:hover .x-icon,
 .drag-axis-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_a.png');
+  background: url('icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_a.png');
   _background: none;
 }
 .drag-axis-accu-small-icon.native .x-icon,
 .drag-axis-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_a.png');
+  background: url('icon/drag/small/icon_axis_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_a.png');
   _background: none;
 }
 .drag-axis-percent-accu-small-icon .x-icon,
 .drag-axis-percent-accu-small-icon:hover .x-icon,
 .drag-axis-percent-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_pa.png');
+  background: url('icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_pa.png');
   _background: none;
 }
 .drag-axis-percent-accu-small-icon.native .x-icon,
 .drag-axis-percent-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_pa.png');
+  background: url('icon/drag/small/icon_axis_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_pa.png');
   _background: none;
 }
 .drag-axis-compare-small-icon .x-icon,
 .drag-axis-compare-small-icon:hover .x-icon,
 .drag-axis-compare-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_c.png');
+  background: url('icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_c.png');
   _background: none;
 }
 .drag-axis-compare-small-icon.native .x-icon,
 .drag-axis-compare-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_c.png');
+  background: url('icon/drag/small/icon_axis_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_c.png');
   _background: none;
 }
 .drag-axis-fall-small-icon .x-icon,
 .drag-axis-fall-small-icon:hover .x-icon,
 .drag-axis-fall-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_f.png');
+  background: url('icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_f.png');
   _background: none;
 }
 .drag-axis-fall-small-icon.native .x-icon,
 .drag-axis-fall-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_axis_f.png');
+  background: url('icon/drag/small/icon_axis_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_axis_f.png');
   _background: none;
 }
 .drag-bar-small-icon .x-icon,
 .drag-bar-small-icon:hover .x-icon,
 .drag-bar-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar.png');
+  background: url('icon/drag/small/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar.png');
   _background: none;
 }
 .drag-bar-small-icon.native .x-icon,
 .drag-bar-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar.png');
+  background: url('icon/drag/small/icon_bar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar.png');
   _background: none;
 }
 .drag-bar-accu-small-icon .x-icon,
 .drag-bar-accu-small-icon:hover .x-icon,
 .drag-bar-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_a.png');
+  background: url('icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_a.png');
   _background: none;
 }
 .drag-bar-accu-small-icon.native .x-icon,
 .drag-bar-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_a.png');
+  background: url('icon/drag/small/icon_bar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_a.png');
   _background: none;
 }
 .drag-bar-compare-small-icon .x-icon,
 .drag-bar-compare-small-icon:hover .x-icon,
 .drag-bar-compare-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_c.png');
+  background: url('icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_c.png');
   _background: none;
 }
 .drag-bar-compare-small-icon.native .x-icon,
 .drag-bar-compare-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bar_c.png');
+  background: url('icon/drag/small/icon_bar_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bar_c.png');
   _background: none;
 }
 .drag-area-small-icon .x-icon,
 .drag-area-small-icon:hover .x-icon,
 .drag-area-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area.png');
+  background: url('icon/drag/small/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area.png');
   _background: none;
 }
 .drag-area-small-icon.native .x-icon,
 .drag-area-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area.png');
+  background: url('icon/drag/small/icon_area.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area.png');
   _background: none;
 }
 .drag-area-accu-small-icon .x-icon,
 .drag-area-accu-small-icon:hover .x-icon,
 .drag-area-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_a.png');
+  background: url('icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_a.png');
   _background: none;
 }
 .drag-area-accu-small-icon.native .x-icon,
 .drag-area-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_a.png');
+  background: url('icon/drag/small/icon_area_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_a.png');
   _background: none;
 }
 .drag-area-percent-accu-small-icon .x-icon,
 .drag-area-percent-accu-small-icon:hover .x-icon,
 .drag-area-percent-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_pa.png');
+  background: url('icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_pa.png');
   _background: none;
 }
 .drag-area-percent-accu-small-icon.native .x-icon,
 .drag-area-percent-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_pa.png');
+  background: url('icon/drag/small/icon_area_pa.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_pa.png');
   _background: none;
 }
 .drag-area-compare-small-icon .x-icon,
 .drag-area-compare-small-icon:hover .x-icon,
 .drag-area-compare-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_c.png');
+  background: url('icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_c.png');
   _background: none;
 }
 .drag-area-compare-small-icon.native .x-icon,
 .drag-area-compare-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_c.png');
+  background: url('icon/drag/small/icon_area_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_c.png');
   _background: none;
 }
 .drag-area-range-small-icon .x-icon,
 .drag-area-range-small-icon:hover .x-icon,
 .drag-area-range-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_r.png');
+  background: url('icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_r.png');
   _background: none;
 }
 .drag-area-range-small-icon.native .x-icon,
 .drag-area-range-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_area_r.png');
+  background: url('icon/drag/small/icon_area_r.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_area_r.png');
   _background: none;
 }
 .drag-combine-small-icon .x-icon,
 .drag-combine-small-icon:hover .x-icon,
 .drag-combine-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine.png');
+  background: url('icon/drag/small/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine.png');
   _background: none;
 }
 .drag-combine-small-icon.native .x-icon,
 .drag-combine-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine.png');
+  background: url('icon/drag/small/icon_combine.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine.png');
   _background: none;
 }
 .drag-combine-mult-small-icon .x-icon,
 .drag-combine-mult-small-icon:hover .x-icon,
 .drag-combine-mult-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine_m.png');
+  background: url('icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine_m.png');
   _background: none;
 }
 .drag-combine-mult-small-icon.native .x-icon,
 .drag-combine-mult-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_combine_m.png');
+  background: url('icon/drag/small/icon_combine_m.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_combine_m.png');
   _background: none;
 }
 .drag-line-small-icon .x-icon,
 .drag-line-small-icon:hover .x-icon,
 .drag-line-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_line.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_line.png');
+  background: url('icon/drag/small/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_line.png');
   _background: none;
 }
 .drag-line-small-icon.native .x-icon,
 .drag-line-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_line.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_line.png');
+  background: url('icon/drag/small/icon_line.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_line.png');
   _background: none;
 }
 .drag-pie-small-icon .x-icon,
 .drag-pie-small-icon:hover .x-icon,
 .drag-pie-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_pie.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_pie.png');
+  background: url('icon/drag/small/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_pie.png');
   _background: none;
 }
 .drag-pie-small-icon.native .x-icon,
 .drag-pie-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_pie.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_pie.png');
+  background: url('icon/drag/small/icon_pie.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_pie.png');
   _background: none;
 }
 .drag-map-china-small-icon .x-icon,
 .drag-map-china-small-icon:hover .x-icon,
 .drag-map-china-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_c.png');
+  background: url('icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_c.png');
   _background: none;
 }
 .drag-map-china-small-icon.native .x-icon,
 .drag-map-china-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_c.png');
+  background: url('icon/drag/small/icon_map_c.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_c.png');
   _background: none;
 }
 .drag-map-global-small-icon .x-icon,
 .drag-map-global-small-icon:hover .x-icon,
 .drag-map-global-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_g.png');
+  background: url('icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_g.png');
   _background: none;
 }
 .drag-map-global-small-icon.native .x-icon,
 .drag-map-global-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_g.png');
+  background: url('icon/drag/small/icon_map_g.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_g.png');
   _background: none;
 }
 .drag-map-svg-small-icon .x-icon,
 .drag-map-svg-small-icon:hover .x-icon,
 .drag-map-svg-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_s.png');
+  background: url('icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_s.png');
   _background: none;
 }
 .drag-map-svg-small-icon.native .x-icon,
 .drag-map-svg-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_s.png');
+  background: url('icon/drag/small/icon_map_s.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_s.png');
   _background: none;
 }
 .drag-map-gis-small-icon .x-icon,
 .drag-map-gis-small-icon:hover .x-icon,
 .drag-map-gis-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_gis.png');
+  background: url('icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_gis.png');
   _background: none;
 }
 .drag-map-gis-small-icon.native .x-icon,
 .drag-map-gis-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_map_gis.png');
+  background: url('icon/drag/small/icon_map_gis.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_map_gis.png');
   _background: none;
 }
 .drag-dashboard-small-icon .x-icon,
 .drag-dashboard-small-icon:hover .x-icon,
 .drag-dashboard-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_dashboard.png');
+  background: url('icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_dashboard.png');
   _background: none;
 }
 .drag-dashboard-small-icon.native .x-icon,
 .drag-dashboard-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_dashboard.png');
+  background: url('icon/drag/small/icon_dashboard.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_dashboard.png');
   _background: none;
 }
 .drag-donut-small-icon .x-icon,
 .drag-donut-small-icon:hover .x-icon,
 .drag-donut-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_donut.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_donut.png');
+  background: url('icon/drag/small/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_donut.png');
   _background: none;
 }
 .drag-donut-small-icon.native .x-icon,
 .drag-donut-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_donut.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_donut.png');
+  background: url('icon/drag/small/icon_donut.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_donut.png');
   _background: none;
 }
 .drag-radar-small-icon .x-icon,
 .drag-radar-small-icon:hover .x-icon,
 .drag-radar-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar.png');
+  background: url('icon/drag/small/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar.png');
   _background: none;
 }
 .drag-radar-small-icon.native .x-icon,
 .drag-radar-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar.png');
+  background: url('icon/drag/small/icon_radar.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar.png');
   _background: none;
 }
 .drag-radar-accu-small-icon .x-icon,
 .drag-radar-accu-small-icon:hover .x-icon,
 .drag-radar-accu-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar_a.png');
+  background: url('icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar_a.png');
   _background: none;
 }
 .drag-radar-accu-small-icon.native .x-icon,
 .drag-radar-accu-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_radar_a.png');
+  background: url('icon/drag/small/icon_radar_a.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_radar_a.png');
   _background: none;
 }
 .drag-bubble-small-icon .x-icon,
 .drag-bubble-small-icon:hover .x-icon,
 .drag-bubble-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble.png');
+  background: url('icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble.png');
   _background: none;
 }
 .drag-bubble-small-icon.native .x-icon,
 .drag-bubble-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble.png');
+  background: url('icon/drag/small/icon_bubble.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble.png');
   _background: none;
 }
 .drag-bubble-force-small-icon .x-icon,
 .drag-bubble-force-small-icon:hover .x-icon,
 .drag-bubble-force-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble_f.png');
+  background: url('icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble_f.png');
   _background: none;
 }
 .drag-bubble-force-small-icon.native .x-icon,
 .drag-bubble-force-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_bubble_f.png');
+  background: url('icon/drag/small/icon_bubble_f.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_bubble_f.png');
   _background: none;
 }
 .drag-scatter-small-icon .x-icon,
 .drag-scatter-small-icon:hover .x-icon,
 .drag-scatter-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_scatter.png');
+  background: url('icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_scatter.png');
   _background: none;
 }
 .drag-scatter-small-icon.native .x-icon,
 .drag-scatter-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_scatter.png');
+  background: url('icon/drag/small/icon_scatter.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_scatter.png');
   _background: none;
 }
 .drag-funnel-small-icon .x-icon,
 .drag-funnel-small-icon:hover .x-icon,
 .drag-funnel-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_funnel.png');
+  background: url('icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_funnel.png');
   _background: none;
 }
 .drag-funnel-small-icon.native .x-icon,
 .drag-funnel-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_funnel.png');
+  background: url('icon/drag/small/icon_funnel.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_funnel.png');
   _background: none;
 }
 .drag-detail-small-icon .x-icon,
 .drag-detail-small-icon:hover .x-icon,
 .drag-detail-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_detail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_detail.png');
+  background: url('icon/drag/small/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_detail.png');
   _background: none;
 }
 .drag-detail-small-icon.native .x-icon,
 .drag-detail-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_detail.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_detail.png');
+  background: url('icon/drag/small/icon_detail.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_detail.png');
   _background: none;
 }
 .drag-input-small-icon .x-icon,
 .drag-input-small-icon:hover .x-icon,
 .drag-input-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_input.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_input.png');
+  background: url('icon/drag/small/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_input.png');
   _background: none;
 }
 .drag-input-small-icon.native .x-icon,
 .drag-input-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_input.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_input.png');
+  background: url('icon/drag/small/icon_input.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_input.png');
   _background: none;
 }
 .drag-web-small-icon .x-icon,
 .drag-web-small-icon:hover .x-icon,
 .drag-web-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_web.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_web.png');
+  background: url('icon/drag/small/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_web.png');
   _background: none;
 }
 .drag-web-small-icon.native .x-icon,
 .drag-web-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_web.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_web.png');
+  background: url('icon/drag/small/icon_web.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_web.png');
   _background: none;
 }
 .drag-image-small-icon .x-icon,
 .drag-image-small-icon:hover .x-icon,
 .drag-image-small-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_image.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_image.png');
+  background: url('icon/drag/small/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_image.png');
   _background: none;
 }
 .drag-image-small-icon.native .x-icon,
 .drag-image-small-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_image.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/drag/small/icon_image.png');
+  background: url('icon/drag/small/icon_image.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/drag/small/icon_image.png');
   _background: none;
 }
 .error-face-icon .x-icon,
 .error-face-icon:hover .x-icon,
 .error-face-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png');
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
   _background: none;
 }
 .error-face-icon.native .x-icon,
 .error-face-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/no_data.png');
+  background: url('icon/no_data.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/no_data.png');
   _background: none;
 }
 .drag-tip-dots-icon .x-icon,
 .drag-tip-dots-icon:hover .x-icon,
 .drag-tip-dots-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/dots.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/dots.png');
+  background: url('icon/dots.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/dots.png');
   _background: none;
 }
 .drag-tip-dots-icon.native .x-icon,
 .drag-tip-dots-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/dots.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/dots.png');
+  background: url('icon/dots.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/dots.png');
   _background: none;
 }
 .bubble-no-projector .x-icon,
 .bubble-no-projector:hover .x-icon,
 .bubble-no-projector:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_no_projector.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_no_projector.png');
+  background: url('icon/bubble_no_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_no_projector.png');
   _background: none;
 }
 .bubble-no-projector.native .x-icon,
 .bubble-no-projector.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_no_projector.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_no_projector.png');
+  background: url('icon/bubble_no_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_no_projector.png');
   _background: none;
 }
 .bubble-with-projector .x-icon,
 .bubble-with-projector:hover .x-icon,
 .bubble-with-projector:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_projector.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_projector.png');
+  background: url('icon/bubble_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_projector.png');
   _background: none;
 }
 .bubble-with-projector.native .x-icon,
 .bubble-with-projector.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_projector.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/bubble_projector.png');
+  background: url('icon/bubble_projector.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/bubble_projector.png');
   _background: none;
 }
 .drill-push-down-icon .x-icon,
 .drill-push-down-icon:hover .x-icon,
 .drill-push-down-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_down.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_down.png');
+  background: url('icon/push_down.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_down.png');
   _background: none;
 }
 .drill-push-down-icon.native .x-icon,
 .drill-push-down-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_down.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_down.png');
+  background: url('icon/push_down.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_down.png');
   _background: none;
 }
 .drill-push-up-icon .x-icon,
 .drill-push-up-icon:hover .x-icon,
 .drill-push-up-icon:active .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_up.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_up.png');
+  background: url('icon/push_up.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_up.png');
   _background: none;
 }
 .drill-push-up-icon.native .x-icon,
 .drill-push-up-icon.disabled .x-icon {
   display: block;
-  background: url('${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_up.png') no-repeat 0px 0px;
-  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/push_up.png');
+  background: url('icon/push_up.png') no-repeat 0px 0px;
+  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='icon/push_up.png');
   _background: none;
 }
diff --git a/src/css/widget/arrangement/arrangement.block.css b/src/css/widget/arrangement/arrangement.block.css
new file mode 100644
index 000000000..69b801736
--- /dev/null
+++ b/src/css/widget/arrangement/arrangement.block.css
@@ -0,0 +1,8 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement-block {
+  background: #e85050;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
diff --git a/src/css/widget/arrangement/arrangement.css b/src/css/widget/arrangement/arrangement.css
new file mode 100644
index 000000000..ee99b7986
--- /dev/null
+++ b/src/css/widget/arrangement/arrangement.css
@@ -0,0 +1,40 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement .arrangement-helper {
+  border: 1px solid #d4dadd;
+  background: #009de3;
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-block {
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-drop-container {
+  z-index: 1000000000;
+}
+.bi-arrangement .arrangement-drop-container .arrangement-drop-region {
+  overflow: hidden;
+}
+.bi-arrangement .arrangement-drop-container .drop-devider {
+  z-index: 1000000001;
+  background: #009de3;
+}
+.bi-arrangement .arrangement-drop-container .top-left,
+.bi-arrangement .arrangement-drop-container .top-right,
+.bi-arrangement .arrangement-drop-container .bottom-left,
+.bi-arrangement .arrangement-drop-container .bottom-right,
+.bi-arrangement .arrangement-drop-container .top-left-second,
+.bi-arrangement .arrangement-drop-container .top-right-second,
+.bi-arrangement .arrangement-drop-container .bottom-left-second,
+.bi-arrangement .arrangement-drop-container .bottom-right-second,
+.bi-arrangement .arrangement-drop-container .top-center,
+.bi-arrangement .arrangement-drop-container .bottom-center,
+.bi-arrangement .arrangement-drop-container .left-center,
+.bi-arrangement .arrangement-drop-container .right-center,
+.bi-arrangement .arrangement-drop-container .top-center-second,
+.bi-arrangement .arrangement-drop-container .bottom-center-second,
+.bi-arrangement .arrangement-drop-container .left-center-second,
+.bi-arrangement .arrangement-drop-container .right-center-second {
+  z-index: 1000000001;
+  background: #009de3;
+}
diff --git a/src/css/widget/arrangement/arrangement.droppable.css b/src/css/widget/arrangement/arrangement.droppable.css
new file mode 100644
index 000000000..2ae94e0f7
--- /dev/null
+++ b/src/css/widget/arrangement/arrangement.droppable.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-arrangement-droppable {
+  background: #d8f3fe;
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+  z-index: 100000;
+}
diff --git a/src/css/widget/base/combo/iconcombo/combo.icon.css b/src/css/widget/base/combo/iconcombo/combo.icon.css
new file mode 100644
index 000000000..c825b6e90
--- /dev/null
+++ b/src/css/widget/base/combo/iconcombo/combo.icon.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-icon-combo.bi-combo-popup .bi-icon-combo-trigger .b-font:before {
+  color: #009de3;
+}
diff --git a/src/css/widget/base/editor/editor.adapt.css b/src/css/widget/base/editor/editor.adapt.css
new file mode 100644
index 000000000..70e3792fe
--- /dev/null
+++ b/src/css/widget/base/editor/editor.adapt.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-adapt-editor .adapt-editor-text {
+  font-size: 14px;
+}
diff --git a/src/css/widget/base/editor/editor.search.css b/src/css/widget/base/editor/editor.search.css
new file mode 100644
index 000000000..0070eff5a
--- /dev/null
+++ b/src/css/widget/base/editor/editor.search.css
@@ -0,0 +1,13 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
+.bi-search-editor {
+  border: 1px solid #d4dadd;
+}
+.bi-search-editor .close-font {
+  font-size: 20px;
+}
+.bi-search-editor .search-font {
+  font-size: 20px;
+}
diff --git a/src/css/widget/base/editor/editor.search.small.css b/src/css/widget/base/editor/editor.search.small.css
new file mode 100644
index 000000000..75ffc8c06
--- /dev/null
+++ b/src/css/widget/base/editor/editor.search.small.css
@@ -0,0 +1,19 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
+.bi-small-search-editor .bi-editor {
+  font-size: 12px;
+}
+.bi-small-search-editor .bi-editor .bi-input {
+  font-size: 12px;
+}
+.bi-small-search-editor .bi-editor .bi-label {
+  font-size: 12px;
+}
+.bi-small-search-editor .close-font {
+  font-size: 18px;
+}
+.bi-small-search-editor .search-font {
+  font-size: 18px;
+}
diff --git a/src/css/widget/base/editor/editor.sign.initial.css b/src/css/widget/base/editor/editor.sign.initial.css
new file mode 100644
index 000000000..e1bb436f7
--- /dev/null
+++ b/src/css/widget/base/editor/editor.sign.initial.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sign-initial-editor .sign-initial-editor-text {
+  font-size: 14px;
+}
diff --git a/src/css/widget/base/editor/editor.sign.style.css b/src/css/widget/base/editor/editor.sign.style.css
new file mode 100644
index 000000000..63e9f258c
--- /dev/null
+++ b/src/css/widget/base/editor/editor.sign.style.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sign-style-editor .sign-style-editor-text {
+  max-width: 100%;
+  font-size: 12px;
+}
+.bi-sign-style-editor .sign-style-editor-tip {
+  max-width: 100%;
+  font-size: 12px;
+  color: #808080;
+}
diff --git a/src/css/widget/base/editor/editor.text.css b/src/css/widget/base/editor/editor.text.css
new file mode 100644
index 000000000..fd41d73a4
--- /dev/null
+++ b/src/css/widget/base/editor/editor.text.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-editor {
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/base/editor/editor.text.small.css b/src/css/widget/base/editor/editor.text.small.css
new file mode 100644
index 000000000..18e55e5ff
--- /dev/null
+++ b/src/css/widget/base/editor/editor.text.small.css
@@ -0,0 +1,4 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+/*************BI.SearchEditor******************/
diff --git a/src/css/widget/base/mask/loading.mask.css b/src/css/widget/base/mask/loading.mask.css
new file mode 100644
index 000000000..ff6723d46
--- /dev/null
+++ b/src/css/widget/base/mask/loading.mask.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-loading-main-background {
+  background-color: #ffffff;
+  opacity: 0.7;
+  filter: alpha(opacity=70);
+}
+.bi-loading-mask-content .loading-bar-label {
+  font-size: 20px;
+  color: #808080;
+}
diff --git a/src/css/widget/base/segment/button.line.segment.css b/src/css/widget/base/segment/button.line.segment.css
new file mode 100644
index 000000000..3d59b575a
--- /dev/null
+++ b/src/css/widget/base/segment/button.line.segment.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-line-segment-button.active .line-segment-button-line {
+  background: #009de3;
+}
+.bi-line-segment-button.disabled,
+.bi-line-segment-button.disabled:hover,
+.bi-line-segment-button.disabled:active {
+  color: #1a1a1a;
+  background: #ffffff;
+}
diff --git a/src/css/widget/base/segment/segment.line.css b/src/css/widget/base/segment/segment.line.css
new file mode 100644
index 000000000..a9ebad60b
--- /dev/null
+++ b/src/css/widget/base/segment/segment.line.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-line-segment {
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/base/tip/tip.helper.css b/src/css/widget/base/tip/tip.helper.css
new file mode 100644
index 000000000..0fad5f96b
--- /dev/null
+++ b/src/css/widget/base/tip/tip.helper.css
@@ -0,0 +1,20 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-helper {
+  background-color: #009de3;
+  font-size: 13px;
+  color: #ffffff;
+  cursor: url('cursor/cursor_drag_hand.cur'), auto;
+  opacity: 0.7;
+}
+.bi-helper.dragging-modify {
+  background: none;
+}
+.bi-helper.dragging-modify .helper-warning {
+  color: #1a1a1a;
+  border: 1px solid #e85050;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/base/toolbar/toolbar.progress.bar.css b/src/css/widget/base/toolbar/toolbar.progress.bar.css
new file mode 100644
index 000000000..fff1ebaae
--- /dev/null
+++ b/src/css/widget/base/toolbar/toolbar.progress.bar.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar-bar {
+  background: #eaeaea;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  border-radius: 20px;
+}
diff --git a/src/css/widget/base/toolbar/toolbar.progress.css b/src/css/widget/base/toolbar/toolbar.progress.css
new file mode 100644
index 000000000..ee1456d14
--- /dev/null
+++ b/src/css/widget/base/toolbar/toolbar.progress.css
@@ -0,0 +1,11 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar .progress-bar-label {
+  font-weight: bold;
+  font-family: "微软雅黑";
+  color: #009de3;
+}
+.bi-progress-bar .progress-bar-label.success {
+  color: #0c6d23;
+}
diff --git a/src/css/widget/base/toolbar/toolbar.progress.processor.css b/src/css/widget/base/toolbar/toolbar.progress.processor.css
new file mode 100644
index 000000000..552b25476
--- /dev/null
+++ b/src/css/widget/base/toolbar/toolbar.progress.processor.css
@@ -0,0 +1,14 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-progress-bar-processor {
+  background: #009de3;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  border-radius: 20px;
+  overflow-x: hidden;
+  overflow-y: hidden;
+}
+.bi-progress-bar-processor.success {
+  background: #58cc7d;
+}
diff --git a/src/css/widget/colorchooser/colorchooser.popup.css b/src/css/widget/colorchooser/colorchooser.popup.css
new file mode 100644
index 000000000..cfaf63670
--- /dev/null
+++ b/src/css/widget/colorchooser/colorchooser.popup.css
@@ -0,0 +1,13 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-chooser-popup .color-chooser-popup-title {
+  background: #f4f4f4;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-color-chooser-popup .color-chooser-popup-more {
+  background: #f4f4f4;
+}
+.bi-color-chooser-popup .color-chooser-popup-more:hover {
+  background: #d4dadd;
+}
diff --git a/src/css/widget/colorchooser/colorchooser.trigger.css b/src/css/widget/colorchooser/colorchooser.trigger.css
new file mode 100644
index 000000000..65be3f196
--- /dev/null
+++ b/src/css/widget/colorchooser/colorchooser.trigger.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-color-chooser-trigger {
+  background: #ffffff;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -webkit-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+  -moz-box-shadow: 0px 0px 2px 1px #d4dadd inset;
+}
diff --git a/src/css/widget/copy2group/button.add.copy2group.css b/src/css/widget/copy2group/button.add.copy2group.css
new file mode 100644
index 000000000..527a2c526
--- /dev/null
+++ b/src/css/widget/copy2group/button.add.copy2group.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-copy2group-add-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #fff5c1;
+}
diff --git a/src/css/widget/copy2group/combo.copy2group.css b/src/css/widget/copy2group/combo.copy2group.css
new file mode 100644
index 000000000..426daff8e
--- /dev/null
+++ b/src/css/widget/copy2group/combo.copy2group.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.copy2_group_search_pane {
+  background: #ffffff;
+}
diff --git a/src/css/widget/date/calendar/picker.date.css b/src/css/widget/date/calendar/picker.date.css
new file mode 100644
index 000000000..6a76b7b14
--- /dev/null
+++ b/src/css/widget/date/calendar/picker.date.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-picker {
+  background: #f4f4f4;
+}
diff --git a/src/css/widget/date/trigger.date.css b/src/css/widget/date/trigger.date.css
new file mode 100644
index 000000000..c7b947b94
--- /dev/null
+++ b/src/css/widget/date/trigger.date.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/downlist/combo.downlist.css b/src/css/widget/downlist/combo.downlist.css
new file mode 100644
index 000000000..edfed09c6
--- /dev/null
+++ b/src/css/widget/downlist/combo.downlist.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item .b-font:before {
+  background-color: #f4f4f4;
+}
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item:disabled,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item.disabled,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item:disabled .b-font:before,
+.bi-down-list-combo .down-list-group.bi-combo-hover .bi-down-list-group-item.disabled .b-font:before {
+  background-color: #ffffff;
+}
+.bi-down-list-combo .bi-down-list-spliter {
+  border-top: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/downlist/popup.downlist.css b/src/css/widget/downlist/popup.downlist.css
new file mode 100644
index 000000000..0d6086147
--- /dev/null
+++ b/src/css/widget/downlist/popup.downlist.css
@@ -0,0 +1,19 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-down-list-popup .bi-down-list-item:hover,
+.bi-down-list-popup .bi-down-list-item.hover {
+  background-color: #f4f4f4;
+}
+.bi-down-list-popup .bi-down-list-item.disabled,
+.bi-down-list-popup .bi-down-list-item.disabled:hover,
+.bi-down-list-popup .bi-down-list-item.disabled:active {
+  background-color: #ffffff;
+}
+.bi-down-list-popup .bi-down-list-item:active {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-down-list-popup .bi-down-list-item .list-item-text {
+  max-width: 203px;
+}
diff --git a/src/css/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.css b/src/css/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.css
new file mode 100644
index 000000000..5ba208022
--- /dev/null
+++ b/src/css/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.css
@@ -0,0 +1,13 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sheet-tab-dynamic-button {
+  background: #eaeaea;
+  border-top: 1px solid #d4dadd;
+}
+.bi-sheet-tab-dynamic-button .bi-icon-button-scroll {
+  border: 1px solid #eaeaea;
+}
+.bi-sheet-tab-dynamic-button .bi-icon-button-scroll:hover {
+  border-color: #d4dadd;
+}
diff --git a/src/css/widget/exceltable/exceltable.cell.css b/src/css/widget/exceltable/exceltable.cell.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/exceltable/exceltable.cell.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/exceltable/exceltable.css b/src/css/widget/exceltable/exceltable.css
new file mode 100644
index 000000000..90a35f20e
--- /dev/null
+++ b/src/css/widget/exceltable/exceltable.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-excel-table > div.bottom-right > div > div > table {
+  border-right: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/exceltable/exceltable.header.cell.css b/src/css/widget/exceltable/exceltable.header.cell.css
new file mode 100644
index 000000000..94c48f0c8
--- /dev/null
+++ b/src/css/widget/exceltable/exceltable.header.cell.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-excel-table-header-cell {
+  font-weight: bold;
+  background-color: #eaeaea;
+}
diff --git a/src/css/widget/filemanager/filemanager.css b/src/css/widget/filemanager/filemanager.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/filemanager/filemanager.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/filemanager/items/item.file.filemanager.css b/src/css/widget/filemanager/items/item.file.filemanager.css
new file mode 100644
index 000000000..4d8cf6ce5
--- /dev/null
+++ b/src/css/widget/filemanager/items/item.file.filemanager.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-file-item {
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/filemanager/items/item.folder.filemanager.css b/src/css/widget/filemanager/items/item.folder.filemanager.css
new file mode 100644
index 000000000..e47e3507c
--- /dev/null
+++ b/src/css/widget/filemanager/items/item.folder.filemanager.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-folder-item {
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/filemanager/nav/button/button.nav.filemanager.css b/src/css/widget/filemanager/nav/button/button.nav.filemanager.css
new file mode 100644
index 000000000..27a5e2807
--- /dev/null
+++ b/src/css/widget/filemanager/nav/button/button.nav.filemanager.css
@@ -0,0 +1,14 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-nav-button .file-manager-nav-button-text {
+  max-width: 200px;
+  background: #ffffff;
+}
+.bi-file-manager-nav-button .file-manager-nav-button-text.active {
+  background-color: #f4f4f4;
+  color: #808080;
+}
+.bi-file-manager-nav-button .file-manager-nav-button-triangle {
+  z-index: 1;
+}
diff --git a/src/css/widget/filemanager/nav/nav.filemanager.css b/src/css/widget/filemanager/nav/nav.filemanager.css
new file mode 100644
index 000000000..952e09390
--- /dev/null
+++ b/src/css/widget/filemanager/nav/nav.filemanager.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-file-manager-nav {
+  border-left: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/filterpane/abstract.item.filter.css b/src/css/widget/filterpane/abstract.item.filter.css
new file mode 100644
index 000000000..878dccf2b
--- /dev/null
+++ b/src/css/widget/filterpane/abstract.item.filter.css
@@ -0,0 +1,14 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-item {
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-filter-item .filter-item-empty-item {
+  border-top: 1px solid #d4dadd;
+}
+.bi-filter-item .filter-item-empty-item .empty-filter-item-leaf {
+  border: 1px dashed #178cdf;
+  background: #58cc7d;
+}
diff --git a/src/css/widget/filterpane/expander.filter.css b/src/css/widget/filterpane/expander.filter.css
new file mode 100644
index 000000000..456fb1949
--- /dev/null
+++ b/src/css/widget/filterpane/expander.filter.css
@@ -0,0 +1,21 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-expander {
+  min-width: 100%;
+  border-right: 0px;
+  border-bottom: 0px;
+}
+.bi-filter-expander > .filter-item-empty-item {
+  border-top: 0px;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-filter-expander > table {
+  min-width: 100%;
+}
+.bi-filter-expander > table > tbody > tr > td.first-element {
+  width: 20px;
+  border-right: 1px solid #d4dadd !important;
+  border-bottom: 1px solid #d4dadd !important;
+}
diff --git a/src/css/widget/filterpane/pane.filter.css b/src/css/widget/filterpane/pane.filter.css
new file mode 100644
index 000000000..b4925510f
--- /dev/null
+++ b/src/css/widget/filterpane/pane.filter.css
@@ -0,0 +1,15 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-filter-pane {
+  min-width: 100%;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border-top: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+}
+.bi-filter-pane .condition-container {
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/finetuningnumbereditor/finetuning.number.editor.css b/src/css/widget/finetuningnumbereditor/finetuning.number.editor.css
new file mode 100644
index 000000000..d8afcf239
--- /dev/null
+++ b/src/css/widget/finetuningnumbereditor/finetuning.number.editor.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-fine-tuning-number-editor {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-fine-tuning-number-editor .top-button {
+  border-left: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-fine-tuning-number-editor .bottom-button {
+  border-left: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/formula/editor.search.css b/src/css/widget/formula/editor.search.css
new file mode 100644
index 000000000..e70aecdc1
--- /dev/null
+++ b/src/css/widget/formula/editor.search.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-search-edit {
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/formula/group.symbol.css b/src/css/widget/formula/group.symbol.css
new file mode 100644
index 000000000..243dbd17b
--- /dev/null
+++ b/src/css/widget/formula/group.symbol.css
@@ -0,0 +1,18 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-symbol-group .symbol-button:hover,
+.bi-formula-symbol-group .symbol-button.hover,
+.bi-formula-symbol-group .symbol-button:active,
+.bi-formula-symbol-group .symbol-button.active {
+  color: #009de3;
+  background-color: #f4f4f4;
+  border: 1px solid #d4dadd;
+}
+.bi-formula-symbol-group .symbol-button {
+  color: #009de3;
+  border: 1px solid #ffffff;
+}
+.symbol-group-column {
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/formula/insert.formula.css b/src/css/widget/formula/insert.formula.css
new file mode 100644
index 000000000..7957c6898
--- /dev/null
+++ b/src/css/widget/formula/insert.formula.css
@@ -0,0 +1,26 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-insert .more-function-button {
+  color: #009de3;
+}
+.bi-formula-insert .bi-formula-field-pane {
+  border-top: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
+.bi-formula-insert .bi-formula-editor {
+  border-left: 1px solid #d4dadd;
+  border-top: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+}
+.bi-formula-insert .bi-water-mark {
+  font-size: 14px;
+}
+.bi-formula-insert .proxy_div {
+  font-size: 13px;
+  background-color: #009de3;
+  color: #ffffff;
+  opacity: 0.7;
+  cursor: pointer;
+}
diff --git a/src/css/widget/formula/item.button.text.treeleaf.css b/src/css/widget/formula/item.button.text.treeleaf.css
new file mode 100644
index 000000000..df2339264
--- /dev/null
+++ b/src/css/widget/formula/item.button.text.treeleaf.css
@@ -0,0 +1,19 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-button-text-tree-item:hover,
+.bi-button-text-tree-item.hover {
+  background-color: #f4f4f4;
+}
+.bi-button-text-tree-item.active {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-button-text-tree-item.disabled,
+.bi-button-text-tree-item.disabled:hover,
+.bi-button-text-tree-item.disabled:active {
+  background-color: #ffffff;
+}
+.bi-button-text-tree-item .formula-function-insert-button {
+  color: #009de3;
+}
diff --git a/src/css/widget/formula/pane.function.css b/src/css/widget/formula/pane.function.css
new file mode 100644
index 000000000..612ea26f4
--- /dev/null
+++ b/src/css/widget/formula/pane.function.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-function-pane .style-inner {
+  border-left: 1px solid #d4dadd;
+  border-top: 1px solid #d4dadd;
+}
+.bi-formula-function-pane .style-top {
+  border-top: 1px solid #d4dadd;
+}
+.bi-formula-function-pane .style-left {
+  border-left: 1px solid #d4dadd;
+}
+.bi-formula-function-pane {
+  background-color: #ffffff;
+}
diff --git a/src/css/widget/formula/tree.fieldname.css b/src/css/widget/formula/tree.fieldname.css
new file mode 100644
index 000000000..57851feb8
--- /dev/null
+++ b/src/css/widget/formula/tree.fieldname.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-field-tree {
+  background-color: #f4f4f4;
+}
diff --git a/src/css/widget/formula/tree.function.css b/src/css/widget/formula/tree.function.css
new file mode 100644
index 000000000..158b2053c
--- /dev/null
+++ b/src/css/widget/formula/tree.function.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-formula-function-tree {
+  background-color: #ffffff;
+}
diff --git a/src/css/widget/image/button/href/image.button.href.css b/src/css/widget/image/button/href/image.button.href.css
new file mode 100644
index 000000000..cb133baf9
--- /dev/null
+++ b/src/css/widget/image/button/href/image.button.href.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-image-button-href .image-button-href-icon-button {
+  z-index: 1;
+  font-size: 16px;
+}
diff --git a/src/css/widget/image/button/size/image.button.size.css b/src/css/widget/image/button/size/image.button.size.css
new file mode 100644
index 000000000..9c5a45187
--- /dev/null
+++ b/src/css/widget/image/button/size/image.button.size.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-image-button-size .image-button-size-button-group {
+  font-size: 12px;
+  color: #1a1a1a;
+}
diff --git a/src/css/widget/image/button/upload.css b/src/css/widget/image/button/upload.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/image/button/upload.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/image/uploadimage.css b/src/css/widget/image/uploadimage.css
new file mode 100644
index 000000000..bf0fe2720
--- /dev/null
+++ b/src/css/widget/image/uploadimage.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-upload-image .upload-image-text-button-label {
+  font-size: 14px;
+  color: #c4c6c6;
+}
+.bi-upload-image .upload-image-icon-button {
+  z-index: 1;
+  font-size: 16px;
+  background-color: #ffffff;
+}
+.bi-upload-image .upload-image-delete-label {
+  font-size: 14px;
+  color: #1a1a1a;
+}
diff --git a/src/css/widget/interactivearrangement/interactivearrangement.css b/src/css/widget/interactivearrangement/interactivearrangement.css
new file mode 100644
index 000000000..f7ee4d771
--- /dev/null
+++ b/src/css/widget/interactivearrangement/interactivearrangement.css
@@ -0,0 +1,10 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-interactive-arrangement .interactive-arrangement-dragtag-line {
+  z-index: 1000000000;
+  background-color: #f07d0a;
+}
+.bi-interactive-arrangement .interactive-arrangement-dragtag-icon {
+  z-index: 1000000000;
+}
diff --git a/src/css/widget/listlabel/listlabel.css b/src/css/widget/listlabel/listlabel.css
new file mode 100644
index 000000000..608635c07
--- /dev/null
+++ b/src/css/widget/listlabel/listlabel.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-list-label {
+  font-size: 14px;
+}
+.bi-list-label .list-label-button:hover {
+  color: #e85050;
+}
diff --git a/src/css/widget/month/combo.month.css b/src/css/widget/month/combo.month.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/month/combo.month.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/month/popup.month.css b/src/css/widget/month/popup.month.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/month/popup.month.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/month/trigger.month.css b/src/css/widget/month/trigger.month.css
new file mode 100644
index 000000000..51c4a6c1a
--- /dev/null
+++ b/src/css/widget/month/trigger.month.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-month-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/move2group/button.add.move2group.css b/src/css/widget/move2group/button.add.move2group.css
new file mode 100644
index 000000000..ef36515b5
--- /dev/null
+++ b/src/css/widget/move2group/button.add.move2group.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-move2group-add-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  background: #fff5c1;
+}
diff --git a/src/css/widget/move2group/combo.move2group.css b/src/css/widget/move2group/combo.move2group.css
new file mode 100644
index 000000000..bb2f59142
--- /dev/null
+++ b/src/css/widget/move2group/combo.move2group.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.move2_group_search_pane {
+  background: #ffffff;
+}
diff --git a/src/css/widget/multidate/multidate.combo.css b/src/css/widget/multidate/multidate.combo.css
new file mode 100644
index 000000000..44b124789
--- /dev/null
+++ b/src/css/widget/multidate/multidate.combo.css
@@ -0,0 +1,8 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-combo {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/multidate/multidate.day.css b/src/css/widget/multidate/multidate.day.css
new file mode 100644
index 000000000..3d6b4e284
--- /dev/null
+++ b/src/css/widget/multidate/multidate.day.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-daycard .bi-multidate-inner-label {
+  color: #808080;
+}
diff --git a/src/css/widget/multidate/multidate.month.css b/src/css/widget/multidate/multidate.month.css
new file mode 100644
index 000000000..ae2e589c0
--- /dev/null
+++ b/src/css/widget/multidate/multidate.month.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-monthcard .bi-multidate-inner-label {
+  color: #808080;
+}
diff --git a/src/css/widget/multidate/multidate.popup.css b/src/css/widget/multidate/multidate.popup.css
new file mode 100644
index 000000000..1b9941424
--- /dev/null
+++ b/src/css/widget/multidate/multidate.popup.css
@@ -0,0 +1,26 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-popup .bi-multidate-popup-label {
+  color: #009de3;
+  font-size: 14px;
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-top: 1px solid #eaeaea;
+}
+.bi-multidate-popup .bi-multidate-popup-tab {
+  border-bottom: 1px solid #eaeaea;
+}
+.bi-multidate-popup .bi-multidate-popup-item:active,
+.bi-multidate-popup .bi-multidate-popup-item.active {
+  background-color: #009de3;
+  color: #ffffff;
+  -webkit-border-radius: 2px 2px 0 0;
+  -moz-border-radius: 2px 2px 0 0;
+  border-radius: 2px 2px 0 0;
+}
+.bi-multidate-popup .bi-multidate-popup-button {
+  color: #009de3;
+  font-size: 14px;
+  border-top: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/multidate/multidate.quarter.css b/src/css/widget/multidate/multidate.quarter.css
new file mode 100644
index 000000000..7ecb2a43e
--- /dev/null
+++ b/src/css/widget/multidate/multidate.quarter.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-quartercard .bi-multidate-inner-label {
+  color: #808080;
+}
diff --git a/src/css/widget/multidate/multidate.segment.css b/src/css/widget/multidate/multidate.segment.css
new file mode 100644
index 000000000..16cc3e3a7
--- /dev/null
+++ b/src/css/widget/multidate/multidate.segment.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-segment .bi-multidate-normal-label {
+  color: #1a1a1a;
+}
+.bi-multidate-segment .bi-multidate-editor {
+  font-size: 14px;
+}
diff --git a/src/css/widget/multidate/multidate.week.css b/src/css/widget/multidate/multidate.week.css
new file mode 100644
index 000000000..9d1636432
--- /dev/null
+++ b/src/css/widget/multidate/multidate.week.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-weekcard .bi-multidate-inner-label {
+  color: #808080;
+}
diff --git a/src/css/widget/multidate/multidate.year.css b/src/css/widget/multidate/multidate.year.css
new file mode 100644
index 000000000..d6eb34b41
--- /dev/null
+++ b/src/css/widget/multidate/multidate.year.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multidate-yearcard .bi-multidate-inner-label {
+  color: #808080;
+}
diff --git a/src/css/widget/multiselect/check/multiselect.check.pane.css b/src/css/widget/multiselect/check/multiselect.check.pane.css
new file mode 100644
index 000000000..ee98f4e77
--- /dev/null
+++ b/src/css/widget/multiselect/check/multiselect.check.pane.css
@@ -0,0 +1,10 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-check-pane .multi-select-continue-select {
+  background-color: #f4f4f4;
+}
+.bi-multi-select-check-pane .multi-select-check-selected {
+  color: #009de3;
+  text-decoration: underline;
+}
diff --git a/src/css/widget/multiselect/check/multiselect.display.css b/src/css/widget/multiselect/check/multiselect.display.css
new file mode 100644
index 000000000..26e6241c0
--- /dev/null
+++ b/src/css/widget/multiselect/check/multiselect.display.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-display-list {
+  background-color: #f4f4f4;
+}
+.bi-display-list .display-list-item {
+  color: #808080;
+}
diff --git a/src/css/widget/multiselect/multiselect.combo.css b/src/css/widget/multiselect/multiselect.combo.css
new file mode 100644
index 000000000..78e5887e7
--- /dev/null
+++ b/src/css/widget/multiselect/multiselect.combo.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-combo .multi-select-trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
diff --git a/src/css/widget/multiselect/multiselect.popup.view.css b/src/css/widget/multiselect/multiselect.popup.view.css
new file mode 100644
index 000000000..53c841864
--- /dev/null
+++ b/src/css/widget/multiselect/multiselect.popup.view.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-popup-view .multi-select-no-toolbar {
+  color: #c4c6c6;
+}
diff --git a/src/css/widget/multiselect/multiselect.trigger.css b/src/css/widget/multiselect/multiselect.trigger.css
new file mode 100644
index 000000000..3bf97099e
--- /dev/null
+++ b/src/css/widget/multiselect/multiselect.trigger.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
diff --git a/src/css/widget/multiselect/search/multiselect.search.pane.css b/src/css/widget/multiselect/search/multiselect.search.pane.css
new file mode 100644
index 000000000..a717a9144
--- /dev/null
+++ b/src/css/widget/multiselect/search/multiselect.search.pane.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-search-pane {
+  background: #ffffff;
+}
+.bi-multi-select-search-pane .multi-select-toolbar {
+  color: #e85050;
+}
diff --git a/src/css/widget/multiselect/trigger/button.checkselected.css b/src/css/widget/multiselect/trigger/button.checkselected.css
new file mode 100644
index 000000000..5756a2ff7
--- /dev/null
+++ b/src/css/widget/multiselect/trigger/button.checkselected.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-select-check-selected-button {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
diff --git a/src/css/widget/multistringlist/multistringlist.css b/src/css/widget/multistringlist/multistringlist.css
new file mode 100644
index 000000000..dbe888659
--- /dev/null
+++ b/src/css/widget/multistringlist/multistringlist.css
@@ -0,0 +1,8 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-string-list .popup-multi-string-list {
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/multitree/check/multi.tree.check.pane.css b/src/css/widget/multitree/check/multi.tree.check.pane.css
new file mode 100644
index 000000000..e47d209b7
--- /dev/null
+++ b/src/css/widget/multitree/check/multi.tree.check.pane.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-check-pane {
+  background-color: #f4f4f4;
+}
+.bi-multi-tree-check-pane .multi-tree-continue-select {
+  background-color: #f4f4f4;
+}
+.bi-multi-tree-check-pane .multi-tree-check-selected {
+  color: #009de3;
+}
diff --git a/src/css/widget/multitree/display.multi.tree.css b/src/css/widget/multitree/display.multi.tree.css
new file mode 100644
index 000000000..95ed7ce02
--- /dev/null
+++ b/src/css/widget/multitree/display.multi.tree.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-display {
+  background-color: #f4f4f4;
+}
diff --git a/src/css/widget/multitree/multi.tree.combo.css b/src/css/widget/multitree/multi.tree.combo.css
new file mode 100644
index 000000000..8ea67a36f
--- /dev/null
+++ b/src/css/widget/multitree/multi.tree.combo.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-combo .multi-select-trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
diff --git a/src/css/widget/multitree/multi.tree.trigger.css b/src/css/widget/multitree/multi.tree.trigger.css
new file mode 100644
index 000000000..a5d0d76f3
--- /dev/null
+++ b/src/css/widget/multitree/multi.tree.trigger.css
@@ -0,0 +1,22 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
+.bi-multi-tree-trigger .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+.bi-multi-tree-trigger .trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
diff --git a/src/css/widget/multitree/popup.multi.tree.css b/src/css/widget/multitree/popup.multi.tree.css
new file mode 100644
index 000000000..3367584e4
--- /dev/null
+++ b/src/css/widget/multitree/popup.multi.tree.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-popup .popup-view-tree {
+  min-height: 170px;
+}
diff --git a/src/css/widget/multitree/search.multi.tree.css b/src/css/widget/multitree/search.multi.tree.css
new file mode 100644
index 000000000..f5df365cf
--- /dev/null
+++ b/src/css/widget/multitree/search.multi.tree.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-search-pane {
+  background: #ffffff;
+}
diff --git a/src/css/widget/multitree/trigger.multi.tree.css b/src/css/widget/multitree/trigger.multi.tree.css
new file mode 100644
index 000000000..a5d0d76f3
--- /dev/null
+++ b/src/css/widget/multitree/trigger.multi.tree.css
@@ -0,0 +1,22 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px 2px 2px 2px;
+  -moz-border-radius: 2px 2px 2px 2px;
+  border-radius: 2px 2px 2px 2px;
+}
+.bi-multi-tree-trigger .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
+.bi-multi-tree-trigger .trigger-icon-button {
+  border-left: 1px solid #d4dadd;
+  font-size: 16px;
+}
diff --git a/src/css/widget/multitree/trigger/multi.tree.button.checkselected.css b/src/css/widget/multitree/trigger/multi.tree.button.checkselected.css
new file mode 100644
index 000000000..33b983af3
--- /dev/null
+++ b/src/css/widget/multitree/trigger/multi.tree.button.checkselected.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-multi-tree-check-selected-button .trigger-check-selected {
+  border: 1px solid #009de3;
+  -webkit-border-radius: 8px 8px 8px 8px;
+  -moz-border-radius: 8px 8px 8px 8px;
+  border-radius: 8px 8px 8px 8px;
+  color: #009de3;
+  background-color: #ffffff;
+  z-index: 1;
+}
diff --git a/src/css/widget/multitreelist/multitreelist.popup.css b/src/css/widget/multitreelist/multitreelist.popup.css
new file mode 100644
index 000000000..ca53430b7
--- /dev/null
+++ b/src/css/widget/multitreelist/multitreelist.popup.css
@@ -0,0 +1,8 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tree-list-popup {
+  border-left: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/numericalinterval/numericalinterval.css b/src/css/widget/numericalinterval/numericalinterval.css
new file mode 100644
index 000000000..db77eda78
--- /dev/null
+++ b/src/css/widget/numericalinterval/numericalinterval.css
@@ -0,0 +1,52 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-numerical-interval .numerical-interval-small-editor {
+  border-top: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+  border-left: 1px solid #d4dadd;
+  -moz-border-radius-topleft: 2px;
+  -webkit-border-top-left-radius: 2px;
+  -moz-border-radius-bottomleft: 2px;
+  -webkit-border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-editor {
+  border-top: 1px solid #d4dadd;
+  border-bottom: 1px solid #d4dadd;
+  border-right: 1px solid #d4dadd;
+  -moz-border-radius-topright: 2px;
+  -webkit-border-top-right-radius: 2px;
+  -moz-border-radius-bottomright: 2px;
+  -webkit-border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-combo {
+  border: 1px solid #d4dadd;
+  -moz-border-radius-topleft: 2px;
+  -webkit-border-top-left-radius: 2px;
+  -moz-border-radius-bottomleft: 2px;
+  -webkit-border-bottom-left-radius: 2px;
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-big-combo .bi-icon-combo-trigger .icon-combo-trigger-icon {
+  font-size: 14px;
+}
+.bi-numerical-interval .numerical-interval-small-combo {
+  border: 1px solid #d4dadd;
+  -moz-border-radius-topright: 2px;
+  -webkit-border-top-right-radius: 2px;
+  -moz-border-radius-bottomright: 2px;
+  -webkit-border-bottom-right-radius: 2px;
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+.bi-numerical-interval .numerical-interval-small-combo .bi-icon-combo-trigger .icon-combo-trigger-icon {
+  font-size: 14px;
+}
+.bi-numerical-interval.number-error .bi-input {
+  color: #e85050;
+}
diff --git a/src/css/widget/numericalinterval/popup.numericalinterval.css b/src/css/widget/numericalinterval/popup.numericalinterval.css
new file mode 100644
index 000000000..a38f49d30
--- /dev/null
+++ b/src/css/widget/numericalinterval/popup.numericalinterval.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-numerical-interval-popup .numerical-interval-popup-item.hover,
+.bi-numerical-interval-popup .numerical-interval-popup-item:hover {
+  background-color: #f4f4f4;
+}
+.bi-numerical-interval-popup .numerical-interval-popup-item.active,
+.bi-numerical-interval-popup .numerical-interval-popup-item:active {
+  background-color: #f4f4f4;
+  color: #009de3;
+}
diff --git a/src/css/widget/pagetable/pagetable.cell.css b/src/css/widget/pagetable/pagetable.cell.css
new file mode 100644
index 000000000..caa1a6ddc
--- /dev/null
+++ b/src/css/widget/pagetable/pagetable.cell.css
@@ -0,0 +1,11 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-page-table-cell {
+  -webkit-user-select: initial;
+  -khtml-user-select: initial;
+  -moz-user-select: initial;
+  -ms-user-select: initial;
+  -o-user-select: initial;
+  user-select: initial;
+}
diff --git a/src/css/widget/pagetable/pagetable.css b/src/css/widget/pagetable/pagetable.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/pagetable/pagetable.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/paramsettingcombo/datecombo/combo.param.date.css b/src/css/widget/paramsettingcombo/datecombo/combo.param.date.css
new file mode 100644
index 000000000..c45a8dc6c
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/datecombo/combo.param.date.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.css b/src/css/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.css
new file mode 100644
index 000000000..4766b5125
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-date-interval-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/paramsettingcombo/param0.date.item.css b/src/css/widget/paramsettingcombo/param0.date.item.css
new file mode 100644
index 000000000..2034f7137
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/param0.date.item.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param0-date-item .param-label {
+  color: #808080;
+}
diff --git a/src/css/widget/paramsettingcombo/param1.date.item.css b/src/css/widget/paramsettingcombo/param1.date.item.css
new file mode 100644
index 000000000..8c60f0bf8
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/param1.date.item.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param1-date-item .param-label {
+  color: #808080;
+}
diff --git a/src/css/widget/paramsettingcombo/param2.date.item.css b/src/css/widget/paramsettingcombo/param2.date.item.css
new file mode 100644
index 000000000..a4e0bac61
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/param2.date.item.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param2-date-item .param-label {
+  color: #808080;
+}
diff --git a/src/css/widget/paramsettingcombo/yearcombo/combo.param.year.css b/src/css/widget/paramsettingcombo/yearcombo/combo.param.year.css
new file mode 100644
index 000000000..6acdb9e24
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/yearcombo/combo.param.year.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.css b/src/css/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.css
new file mode 100644
index 000000000..ee5a69994
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-month-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.css b/src/css/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.css
new file mode 100644
index 000000000..e5bf6dc88
--- /dev/null
+++ b/src/css/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-season-param-combo .param-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/pathchooser/pathchooser.css b/src/css/widget/pathchooser/pathchooser.css
new file mode 100644
index 000000000..06171e32b
--- /dev/null
+++ b/src/css/widget/pathchooser/pathchooser.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-path-chooser .path-chooser-radio {
+  z-index: 1;
+}
diff --git a/src/css/widget/pathchooser/pathregion.css b/src/css/widget/pathchooser/pathregion.css
new file mode 100644
index 000000000..b068ae1ed
--- /dev/null
+++ b/src/css/widget/pathchooser/pathregion.css
@@ -0,0 +1,15 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-path-region {
+  background: #eaeaea;
+}
+.bi-path-region .path-region-label {
+  z-index: 1;
+  background: #ffffff;
+  border: 1px solid #ffffff;
+}
+.bi-path-region .path-region-label.active {
+  background: #009de3;
+  color: #ffffff;
+}
diff --git a/src/css/widget/previewtable/previewtable.cell.css b/src/css/widget/previewtable/previewtable.cell.css
new file mode 100644
index 000000000..9af2d6d71
--- /dev/null
+++ b/src/css/widget/previewtable/previewtable.cell.css
@@ -0,0 +1,8 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table-cell {
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
diff --git a/src/css/widget/previewtable/previewtable.css b/src/css/widget/previewtable/previewtable.css
new file mode 100644
index 000000000..7d4519ab2
--- /dev/null
+++ b/src/css/widget/previewtable/previewtable.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table > div > table > thead > tr.odd,
+.bi-preview-table > div > div > div > table > thead > tr.odd {
+  background-color: #eaeaea;
+}
diff --git a/src/css/widget/previewtable/previewtable.header.cell.css b/src/css/widget/previewtable/previewtable.header.cell.css
new file mode 100644
index 000000000..3b5af9d0d
--- /dev/null
+++ b/src/css/widget/previewtable/previewtable.header.cell.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-preview-table-header-cell {
+  font-weight: bold;
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
diff --git a/src/css/widget/quarter/combo.quarter.css b/src/css/widget/quarter/combo.quarter.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/quarter/combo.quarter.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/quarter/popup.quarter.css b/src/css/widget/quarter/popup.quarter.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/quarter/popup.quarter.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/quarter/trigger.quarter.css b/src/css/widget/quarter/trigger.quarter.css
new file mode 100644
index 000000000..1e8b3da92
--- /dev/null
+++ b/src/css/widget/quarter/trigger.quarter.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-quarter-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/relationview/relationview.item.css b/src/css/widget/relationview/relationview.item.css
new file mode 100644
index 000000000..21294ea02
--- /dev/null
+++ b/src/css/widget/relationview/relationview.item.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-relation-view-item.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
diff --git a/src/css/widget/relationview/relationview.region.css b/src/css/widget/relationview/relationview.region.css
new file mode 100644
index 000000000..dceee5cf6
--- /dev/null
+++ b/src/css/widget/relationview/relationview.region.css
@@ -0,0 +1,17 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-relation-view-region .relation-view-region-container {
+  background: #ffffff;
+  border: 1px solid #d4dadd;
+  z-index: 1;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-relation-view-region .relation-view-region-container.other-package {
+  border: 1px dashed #d4dadd;
+}
+.bi-relation-view-region .relation-view-region-container .relation-view-region-title {
+  border-bottom: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/selectdata/searchpane/result.search.selectdata.css b/src/css/widget/selectdata/searchpane/result.search.selectdata.css
new file mode 100644
index 000000000..5ed101bfb
--- /dev/null
+++ b/src/css/widget/selectdata/searchpane/result.search.selectdata.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-search-result-pane .search-result-line {
+  border-top: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/selectdata/searchpane/searcher.selectdata.css b/src/css/widget/selectdata/searchpane/searcher.selectdata.css
new file mode 100644
index 000000000..fd6819ddb
--- /dev/null
+++ b/src/css/widget/selectdata/searchpane/searcher.selectdata.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-searcher {
+  font-size: 13px;
+}
diff --git a/src/css/widget/selectdata/searchpane/segment.search.selectdata.css b/src/css/widget/selectdata/searchpane/segment.search.selectdata.css
new file mode 100644
index 000000000..a70336b54
--- /dev/null
+++ b/src/css/widget/selectdata/searchpane/segment.search.selectdata.css
@@ -0,0 +1,13 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-search-segment .search-segment-field-table > .first-element {
+  -webkit-border-radius: 3px 0px 0px 3px;
+  -moz-border-radius: 3px 0px 0px 3px;
+  border-radius: 3px 0px 0px 3px;
+}
+.bi-select-data-search-segment .search-segment-field-table > .last-element {
+  -webkit-border-radius: 0px 3 3px 0px;
+  -moz-border-radius: 0px 3 3px 0px;
+  border-radius: 0px 3 3px 0px;
+}
diff --git a/src/css/widget/selectdata/searchpane/tab.search.selectdata.css b/src/css/widget/selectdata/searchpane/tab.search.selectdata.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/selectdata/searchpane/tab.search.selectdata.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/selectdata/tree/expander.selectdata.css b/src/css/widget/selectdata/tree/expander.selectdata.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/selectdata/tree/expander.selectdata.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/selectdata/tree/node/node.level0.css b/src/css/widget/selectdata/tree/node/node.level0.css
new file mode 100644
index 000000000..ec4b3d5dc
--- /dev/null
+++ b/src/css/widget/selectdata/tree/node/node.level0.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level0-node .select-data-selected-count-label {
+  color: #009de3;
+}
diff --git a/src/css/widget/selectdata/tree/node/node.level1.css b/src/css/widget/selectdata/tree/node/node.level1.css
new file mode 100644
index 000000000..81225a64e
--- /dev/null
+++ b/src/css/widget/selectdata/tree/node/node.level1.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level1-node .select-data-selected-count-label {
+  color: #009de3;
+}
diff --git a/src/css/widget/selectdata/tree/tree.selectdata.css b/src/css/widget/selectdata/tree/tree.selectdata.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/selectdata/tree/tree.selectdata.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/selectdata/tree/treeitem/item.level0.css b/src/css/widget/selectdata/tree/treeitem/item.level0.css
new file mode 100644
index 000000000..af5cf0864
--- /dev/null
+++ b/src/css/widget/selectdata/tree/treeitem/item.level0.css
@@ -0,0 +1,53 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level0-item .select-data-level0-item-button {
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:hover,
+.bi-select-data-level0-item .select-data-level0-item-button.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:active,
+.bi-select-data-level0-item .select-data-level0-item-button.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+.bi-select-data-level0-item .select-data-level0-item-button:active .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.active .bi-high-light {
+  color: #ffffff;
+}
+.bi-select-data-level0-item .select-data-level0-item-button.disabled,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:hover,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:active {
+  color: #c4c6c6 !important;
+  background-color: #ffffff !important;
+}
+.bi-select-data-level0-item .select-data-level0-item-button.disabled .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:hover .bi-high-light,
+.bi-select-data-level0-item .select-data-level0-item-button.disabled:active .bi-high-light {
+  color: #c4c6c6 !important;
+}
+.bi-select-data-level0-item .select-data-top-line,
+.bi-select-data-level0-item .select-data-bottom-line {
+  background-color: #009de3;
+}
+.bi-select-data-level0-item.select-data-item-top .select-data-level0-item-button {
+  -moz-border-radius-topleft: 0;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -webkit-border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.bi-select-data-level0-item.select-data-item-bottom .select-data-level0-item-button {
+  -moz-border-radius-bottomleft: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -moz-border-radius-bottomright: 0;
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
diff --git a/src/css/widget/selectdata/tree/treeitem/item.level1.css b/src/css/widget/selectdata/tree/treeitem/item.level1.css
new file mode 100644
index 000000000..5a01508b4
--- /dev/null
+++ b/src/css/widget/selectdata/tree/treeitem/item.level1.css
@@ -0,0 +1,53 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-select-data-level1-item .select-data-level1-item-button {
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:hover,
+.bi-select-data-level1-item .select-data-level1-item-button.hover {
+  color: #009de3;
+  background-color: #f4f4f4;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:active,
+.bi-select-data-level1-item .select-data-level1-item-button.active {
+  color: #ffffff;
+  background-color: #009de3;
+}
+.bi-select-data-level1-item .select-data-level1-item-button:active .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.active .bi-high-light {
+  color: #ffffff;
+}
+.bi-select-data-level1-item .select-data-level1-item-button.disabled,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:hover,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:active {
+  color: #c4c6c6 !important;
+  background-color: #ffffff !important;
+}
+.bi-select-data-level1-item .select-data-level1-item-button.disabled .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:hover .bi-high-light,
+.bi-select-data-level1-item .select-data-level1-item-button.disabled:active .bi-high-light {
+  color: #c4c6c6 !important;
+}
+.bi-select-data-level1-item .select-data-top-line,
+.bi-select-data-level1-item .select-data-bottom-line {
+  background-color: #009de3;
+}
+.bi-select-data-level1-item.select-data-item-top .select-data-level1-item-button {
+  -moz-border-radius-topleft: 0;
+  -webkit-border-top-left-radius: 0;
+  -moz-border-radius-topright: 0;
+  -webkit-border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.bi-select-data-level1-item.select-data-item-bottom .select-data-level1-item-button {
+  -moz-border-radius-bottomleft: 0;
+  -webkit-border-bottom-left-radius: 0;
+  -moz-border-radius-bottomright: 0;
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
diff --git a/src/css/widget/selecttable/single/button.databasetable.css b/src/css/widget/selecttable/single/button.databasetable.css
new file mode 100644
index 000000000..798b28259
--- /dev/null
+++ b/src/css/widget/selecttable/single/button.databasetable.css
@@ -0,0 +1,80 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-database-table {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+  background: #ffffff;
+}
+.bi-database-table.active {
+  background: #009de3;
+  color: #ffffff;
+}
+.bi-database-table .table-name-text {
+  max-width: 300px;
+}
+.bi-database-table .table-font {
+  font-size: 16px;
+}
+.bi-database-table .table-conn-label1 {
+  background-color: #009de3;
+}
+.bi-database-table .table-conn-label2 {
+  background-color: #4fc1e9;
+}
+.bi-database-table .table-conn-label3 {
+  background-color: #48cfad;
+}
+.bi-database-table .table-conn-label4 {
+  background-color: #57cb7c;
+}
+.bi-database-table .table-conn-label5 {
+  background-color: #a0d468;
+}
+.bi-database-table .table-conn-label6 {
+  background-color: #fbaf4f;
+}
+.bi-database-table .table-conn-label7 {
+  background-color: #fc6e51;
+}
+.bi-database-table .table-conn-label8 {
+  background-color: #ed5565;
+}
+.bi-database-table .table-conn-label9 {
+  background-color: #ac92ec;
+}
+.bi-database-table .table-conn-label10 {
+  background-color: #5d9cec;
+}
+.bi-database-table.table-selected1.active {
+  background-color: #009de3;
+}
+.bi-database-table.table-selected2.active {
+  background-color: #4fc1e9;
+}
+.bi-database-table.table-selected3.active {
+  background-color: #48cfad;
+}
+.bi-database-table.table-selected4.active {
+  background-color: #57cb7c;
+}
+.bi-database-table.table-selected5.active {
+  background-color: #a0d468;
+}
+.bi-database-table.table-selected6.active {
+  background-color: #fbaf4f;
+}
+.bi-database-table.table-selected7.active {
+  background-color: #fc6e51;
+}
+.bi-database-table.table-selected8.active {
+  background-color: #ed5565;
+}
+.bi-database-table.table-selected9.active {
+  background-color: #ac92ec;
+}
+.bi-database-table.table-selected10.active {
+  background-color: #5d9cec;
+}
diff --git a/src/css/widget/selecttree/combo.select.tree.css b/src/css/widget/selecttree/combo.select.tree.css
new file mode 100644
index 000000000..9b6290885
--- /dev/null
+++ b/src/css/widget/selecttree/combo.select.tree.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-selecttree-combo .selecttree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/css/widget/sequencetable/dynamicnumber.sequencetable.css b/src/css/widget/sequencetable/dynamicnumber.sequencetable.css
new file mode 100644
index 000000000..059def484
--- /dev/null
+++ b/src/css/widget/sequencetable/dynamicnumber.sequencetable.css
@@ -0,0 +1,29 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-dynamic-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-dynamic-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/sequencetable/listnumber.sequencetable.css b/src/css/widget/sequencetable/listnumber.sequencetable.css
new file mode 100644
index 000000000..bd987fced
--- /dev/null
+++ b/src/css/widget/sequencetable/listnumber.sequencetable.css
@@ -0,0 +1,29 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-list-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-list-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/sequencetable/sequencetable.css b/src/css/widget/sequencetable/sequencetable.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/sequencetable/sequencetable.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/sequencetable/treenumber.sequencetable.css b/src/css/widget/sequencetable/treenumber.sequencetable.css
new file mode 100644
index 000000000..616a45cfc
--- /dev/null
+++ b/src/css/widget/sequencetable/treenumber.sequencetable.css
@@ -0,0 +1,29 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sequence-table-tree-number .sequence-table-title-cell {
+  overflow-x: hidden;
+  overflow-y: hidden;
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border: 1px solid #eaeaea;
+}
+.bi-sequence-table-tree-number .sequence-table-number-cell {
+  -webkit-box-sizing: border-box;
+  /*Safari3.2+*/
+  -moz-box-sizing: border-box;
+  /*Firefox3.5+*/
+  -ms-box-sizing: border-box;
+  /*IE8*/
+  box-sizing: border-box;
+  /*W3C标准(IE9+,Safari5.1+,Chrome10.0+,Opera10.6+都符合box-sizing的w3c标准语法)*/
+  border-left: 1px solid #eaeaea;
+  border-right: 1px solid #eaeaea;
+  border-bottom: 1px solid #eaeaea;
+}
diff --git a/src/css/widget/singleslider/singleslider.css b/src/css/widget/singleslider/singleslider.css
new file mode 100644
index 000000000..c3456da8c
--- /dev/null
+++ b/src/css/widget/singleslider/singleslider.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-single-slider .slider-editor-button .sign-editor-text:hover {
+  border: 1px solid #d4dadd;
+}
+.bi-single-slider .slider-editor-button .bi-editor {
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/singleslider/slider/widget.slider.css b/src/css/widget/singleslider/slider/widget.slider.css
new file mode 100644
index 000000000..bbf552185
--- /dev/null
+++ b/src/css/widget/singleslider/slider/widget.slider.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-single-slider-slider {
+  cursor: url('cursor/cursor_left_right.cur'), auto;
+}
diff --git a/src/css/widget/singleslider/track/widget.track.css b/src/css/widget/singleslider/track/widget.track.css
new file mode 100644
index 000000000..08d26ca5b
--- /dev/null
+++ b/src/css/widget/singleslider/track/widget.track.css
@@ -0,0 +1,21 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-slider-track .background-track {
+  background-color: #f4f4f4;
+  -webkit-border-radius: 12px;
+  -moz-border-radius: 12px;
+  border-radius: 12px;
+}
+.bi-slider-track .gray-track {
+  background: #cccccc;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
+.bi-slider-track .blue-track {
+  background: #009de3;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
diff --git a/src/css/widget/singletree/combo.single.tree.css b/src/css/widget/singletree/combo.single.tree.css
new file mode 100644
index 000000000..3c017482b
--- /dev/null
+++ b/src/css/widget/singletree/combo.single.tree.css
@@ -0,0 +1,12 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-singletree-combo .singletree-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
+.bi-singletree-combo .bi-singletree-popup .singletree-toolbar {
+  color: #c4c6c6;
+}
diff --git a/src/css/widget/sortabletable/sortabletable.css b/src/css/widget/sortabletable/sortabletable.css
new file mode 100644
index 000000000..7f18220bd
--- /dev/null
+++ b/src/css/widget/sortabletable/sortabletable.css
@@ -0,0 +1,14 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-sortable-table .sortable_table_drag_clone {
+  background: #d8f2fd;
+  top: 0px;
+  opacity: 0.5;
+}
+.bi-sortable-table .drag-header {
+  cursor: move;
+}
+.bi-sortable-table .insert-help-line {
+  border-right: 3px dashed #009de3;
+}
diff --git a/src/css/widget/textarea/textarea.css b/src/css/widget/textarea/textarea.css
new file mode 100644
index 000000000..f6bb7a547
--- /dev/null
+++ b/src/css/widget/textarea/textarea.css
@@ -0,0 +1,7 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-area .text-area-editor-text-button-label {
+  font-size: 16px;
+  color: #c4c6c6;
+}
diff --git a/src/css/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.css b/src/css/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.css
new file mode 100644
index 000000000..58f8b4dcc
--- /dev/null
+++ b/src/css/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-toolbar-align-chooser .align-chooser-button:hover {
+  background-color: #c4c6c6;
+}
+.bi-text-toolbar-align-chooser .align-chooser-button.active {
+  background-color: #c4c6c6;
+}
diff --git a/src/css/widget/texttoolbar/texttoolbar.css b/src/css/widget/texttoolbar/texttoolbar.css
new file mode 100644
index 000000000..688d67d80
--- /dev/null
+++ b/src/css/widget/texttoolbar/texttoolbar.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-text-toolbar {
+  background: #eaeaea;
+}
+.bi-text-toolbar .text-toolbar-button {
+  font-size: 16px;
+}
+.bi-text-toolbar .text-toolbar-size-chooser-trigger {
+  background: #ffffff;
+  font-size: 12px;
+}
+.bi-text-toolbar .text-toolbar-size-chooser-trigger a {
+  font-size: 12px;
+}
diff --git a/src/css/widget/timeinterval/timeinterval.css b/src/css/widget/timeinterval/timeinterval.css
new file mode 100644
index 000000000..f43d57749
--- /dev/null
+++ b/src/css/widget/timeinterval/timeinterval.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-param-time-interval.time-error .bi-input {
+  color: #e85050;
+}
+.bi-param-time-interval.time-error .sign-editor-text {
+  color: #e85050;
+}
diff --git a/src/css/widget/timesetting/timesetting.day.css b/src/css/widget/timesetting/timesetting.day.css
new file mode 100644
index 000000000..a5c627c84
--- /dev/null
+++ b/src/css/widget/timesetting/timesetting.day.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-time-setting-day .operator-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/timesetting/timesetting.hour.css b/src/css/widget/timesetting/timesetting.hour.css
new file mode 100644
index 000000000..7deff31b5
--- /dev/null
+++ b/src/css/widget/timesetting/timesetting.hour.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-time-setting-hour .operator-button {
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+  border: 1px solid #d4dadd;
+}
diff --git a/src/css/widget/treelabel/treelabel.css b/src/css/widget/treelabel/treelabel.css
new file mode 100644
index 000000000..d782c2413
--- /dev/null
+++ b/src/css/widget/treelabel/treelabel.css
@@ -0,0 +1,6 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-tree-label {
+  font-size: 14px;
+}
diff --git a/src/css/widget/treelabel/treelabel.view.css b/src/css/widget/treelabel/treelabel.view.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/treelabel/treelabel.view.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/web/web.css b/src/css/widget/web/web.css
new file mode 100644
index 000000000..16fe67de5
--- /dev/null
+++ b/src/css/widget/web/web.css
@@ -0,0 +1,16 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-web-page .web-page-button {
+  z-index: 1;
+  font-size: 14px;
+  background-color: #ffffff;
+}
+.bi-web-page .web-page-text-button-label {
+  font-size: 16px;
+  color: #c4c6c6;
+}
+.bi-web-page .web-page-delete-label {
+  font-size: 14px;
+  color: #1a1a1a;
+}
diff --git a/src/css/widget/year/combo.year.css b/src/css/widget/year/combo.year.css
new file mode 100644
index 000000000..2f6491e13
--- /dev/null
+++ b/src/css/widget/year/combo.year.css
@@ -0,0 +1,3 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/src/css/widget/year/popup.year.css b/src/css/widget/year/popup.year.css
new file mode 100644
index 000000000..3839717e2
--- /dev/null
+++ b/src/css/widget/year/popup.year.css
@@ -0,0 +1,14 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-popup .year-popup-navigation {
+  border-top: 1px solid #eaeaea;
+  line-height: 30px;
+  color: #009de3;
+}
+.bi-year-popup .year-popup-navigation > .center-element {
+  border-left: 1px solid #eaeaea;
+}
+.bi-year-popup .year-popup-navigation > .first-element {
+  border-left: none;
+}
diff --git a/src/css/widget/year/trigger.year.css b/src/css/widget/year/trigger.year.css
new file mode 100644
index 000000000..72cd98518
--- /dev/null
+++ b/src/css/widget/year/trigger.year.css
@@ -0,0 +1,9 @@
+/****添加计算宽度的--运算符直接需要space****/
+/****** common color(常用颜色,可用于普遍场景) *****/
+/**** custom color(自定义颜色,用于特定场景) ****/
+.bi-year-trigger {
+  border: 1px solid #d4dadd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  border-radius: 2px;
+}
diff --git a/src/data/constant/biconst.js b/src/data/constant/biconst.js
index e69de29bb..ba8ea003b 100644
--- a/src/data/constant/biconst.js
+++ b/src/data/constant/biconst.js
@@ -0,0 +1,464 @@
+BICst.HISTORY_VERSION = {};
+BICst.HISTORY_VERSION.VERSION_4_0 = 4.0;
+BICst.HISTORY_VERSION.VERSION_4_1 = 4.01;
+BICst.REPORT_AUTH = {};
+BICst.REPORT_AUTH.NONE = 0;
+BICst.REPORT_AUTH.EDIT = 1;
+BICst.REPORT_AUTH.VIEW = 2;
+BICst.TARGET_STYLE = {};
+BICst.TARGET_STYLE.ICON_STYLE = {};
+BICst.TARGET_STYLE.ICON_STYLE.NONE = 1;
+BICst.TARGET_STYLE.ICON_STYLE.POINT = 2;
+BICst.TARGET_STYLE.ICON_STYLE.ARROW = 3;
+BICst.TARGET_STYLE.NUM_LEVEL = {};
+BICst.TARGET_STYLE.NUM_LEVEL.NORMAL = 1;
+BICst.TARGET_STYLE.NUM_LEVEL.TEN_THOUSAND = 2;
+BICst.TARGET_STYLE.NUM_LEVEL.MILLION = 3;
+BICst.TARGET_STYLE.NUM_LEVEL.YI = 4;
+BICst.TARGET_STYLE.NUM_LEVEL.PERCENT = 5;
+BICst.TARGET_STYLE.FORMAT = {};
+BICst.TARGET_STYLE.FORMAT.NORMAL = -1;
+BICst.TARGET_STYLE.FORMAT.ZERO2POINT = 0;
+BICst.TARGET_STYLE.FORMAT.ONE2POINT = 1;
+BICst.TARGET_STYLE.FORMAT.TWO2POINT = 2;
+BICst.MULTI_PATH_STATUS = {};
+BICst.MULTI_PATH_STATUS.NEED_GENERATE_CUBE = 0;
+BICst.MULTI_PATH_STATUS.NOT_NEED_GENERATE_CUBE = 1;
+BICst.CUSTOM_GROUP = {};
+BICst.CUSTOM_GROUP.UNGROUP2OTHER = {};
+BICst.CUSTOM_GROUP.UNGROUP2OTHER.NOTSELECTED = 0;
+BICst.CUSTOM_GROUP.UNGROUP2OTHER.SELECTED = 1;
+BICst.REPORT_STATUS = {};
+BICst.REPORT_STATUS.APPLYING = 1;
+BICst.REPORT_STATUS.HANGOUT = 2;
+BICst.REPORT_STATUS.NORMAL = 3;
+BICst.FIELD_ID = {};
+BICst.FIELD_ID.HEAD = "81c48028-1401-11e6-a148-3e1d05defe78";
+BICst.TREE_LABEL = {};
+BICst.TREE_LABEL.TREE_LABEL_ITEM_COUNT_NUM = 40;
+BICst.TREE = {};
+BICst.TREE.TREE_REQ_TYPE = {};
+BICst.TREE.TREE_REQ_TYPE.INIT_DATA = 0;
+BICst.TREE.TREE_REQ_TYPE.SEARCH_DATA = 1;
+BICst.TREE.TREE_REQ_TYPE.SELECTED_DATA = 3;
+BICst.TREE.TREE_REQ_TYPE.ADJUST_DATA = 2;
+BICst.TREE.TREE_REQ_TYPE.DISPLAY_DATA = 4;
+BICst.TREE.TREE_ITEM_COUNT_PER_PAGE = 100;
+BICst.BUSINESS_TABLE_TYPE = {};
+BICst.BUSINESS_TABLE_TYPE.NORMAL = 0;
+BICst.EXPANDER_TYPE = {};
+BICst.EXPANDER_TYPE.NONE = false;
+BICst.EXPANDER_TYPE.ALL = true;
+BICst.SORT = {};
+BICst.SORT.ASC = 0;
+BICst.SORT.DESC = 1;
+BICst.SORT.CUSTOM = 2;
+BICst.SORT.NONE = 3;
+BICst.SORT.NUMBER_ASC = 4;
+BICst.SORT.NUMBER_DESC = 5;
+BICst.TABLE_PAGE_OPERATOR = {};
+BICst.TABLE_PAGE_OPERATOR.ALL_PAGE = -1;
+BICst.TABLE_PAGE_OPERATOR.REFRESH = 0;
+BICst.TABLE_PAGE_OPERATOR.COLUMN_PRE = 1;
+BICst.TABLE_PAGE_OPERATOR.COLUMN_NEXT = 2;
+BICst.TABLE_PAGE_OPERATOR.ROW_PRE = 3;
+BICst.TABLE_PAGE_OPERATOR.ROW_NEXT = 4;
+BICst.TABLE_PAGE_OPERATOR.EXPAND = 5;
+BICst.TABLE_PAGE = {};
+BICst.TABLE_PAGE.VERTICAL_PRE = 0;
+BICst.TABLE_PAGE.VERTICAL_NEXT = 1;
+BICst.TABLE_PAGE.HORIZON_PRE = 2;
+BICst.TABLE_PAGE.HORIZON_NEXT = 3;
+BICst.TABLE_PAGE.TOTAL_PAGE = 4;
+BICst.TABLE_WIDGET = {};
+BICst.TABLE_WIDGET.GROUP_TYPE = 1;
+BICst.TABLE_WIDGET.CROSS_TYPE = 2;
+BICst.TABLE_WIDGET.COMPLEX_TYPE = 3;
+BICst.REGION = {};
+BICst.REGION.DIMENSION1 = "10000";
+BICst.REGION.DIMENSION2 = "20000";
+BICst.REGION.TARGET1 = "30000";
+BICst.REGION.TARGET2 = "40000";
+BICst.REGION.TARGET3 = "50000";
+BICst.EXPORT = {};
+BICst.EXPORT.EXCEL = 1;
+BICst.EXPORT.PDF = 2;
+BICst.WIDGET = {};
+BICst.WIDGET.TABLE = 1;
+BICst.WIDGET.CROSS_TABLE = 2;
+BICst.WIDGET.COMPLEX_TABLE = 3;
+BICst.WIDGET.DETAIL = 4;
+BICst.WIDGET.AXIS = 5;
+BICst.WIDGET.ACCUMULATE_AXIS = 6;
+BICst.WIDGET.PERCENT_ACCUMULATE_AXIS = 7;
+BICst.WIDGET.COMPARE_AXIS = 8;
+BICst.WIDGET.FALL_AXIS = 9;
+BICst.WIDGET.BAR = 10;
+BICst.WIDGET.ACCUMULATE_BAR = 11;
+BICst.WIDGET.COMPARE_BAR = 12;
+BICst.WIDGET.LINE = 13;
+BICst.WIDGET.AREA = 14;
+BICst.WIDGET.ACCUMULATE_AREA = 15;
+BICst.WIDGET.PERCENT_ACCUMULATE_AREA = 16;
+BICst.WIDGET.COMPARE_AREA = 17;
+BICst.WIDGET.RANGE_AREA = 18;
+BICst.WIDGET.COMBINE_CHART = 19;
+BICst.WIDGET.MULTI_AXIS_COMBINE_CHART = 20;
+BICst.WIDGET.PIE = 21;
+BICst.WIDGET.DONUT = 22;
+BICst.WIDGET.MAP = 23;
+BICst.WIDGET.GIS_MAP = 24;
+BICst.WIDGET.DASHBOARD = 25;
+BICst.WIDGET.BUBBLE = 26;
+BICst.WIDGET.FORCE_BUBBLE = 27;
+BICst.WIDGET.SCATTER = 28;
+BICst.WIDGET.RADAR = 29;
+BICst.WIDGET.ACCUMULATE_RADAR = 30;
+BICst.WIDGET.FUNNEL = 31;
+BICst.WIDGET.RECT_TREE = 39;
+BICst.WIDGET.MULTI_PIE = 40;
+BICst.WIDGET.HEAT_MAP = 65;
+BICst.WIDGET.PARETO = 66;
+BICst.WIDGET.STRING = 32;
+BICst.WIDGET.NUMBER = 33;
+BICst.WIDGET.TREE = 34;
+BICst.WIDGET.SINGLE_SLIDER = 35;
+BICst.WIDGET.INTERVAL_SLIDER = 36;
+BICst.WIDGET.LIST_LABEL = 37;
+BICst.WIDGET.TREE_LABEL = 38;
+BICst.WIDGET.STRING_LIST = 59;
+BICst.WIDGET.TREE_LIST = 60;
+BICst.WIDGET.DATE_PANE = 61;
+BICst.WIDGET.DATE = 48;
+BICst.WIDGET.YEAR = 49;
+BICst.WIDGET.QUARTER = 50;
+BICst.WIDGET.MONTH = 51;
+BICst.WIDGET.YMD = 52;
+BICst.WIDGET.QUERY = 53;
+BICst.WIDGET.RESET = 54;
+BICst.WIDGET.CONTENT = 55;
+BICst.WIDGET.IMAGE = 56;
+BICst.WIDGET.WEB = 57;
+BICst.WIDGET.GENERAL_QUERY = 58;
+BICst.WIDGET.TABLE_SHOW = 64;
+BICst.WIDGET.NONE = -1;
+BICst.TARGET_TYPE = {};
+BICst.TARGET_TYPE.CAL_POSITION = {};
+BICst.TARGET_TYPE.CAL_POSITION.ALL = 0;
+BICst.TARGET_TYPE.CAL_POSITION.INGROUP = 1;
+BICst.TARGET_TYPE.CAL_VALUE = {};
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE = {};
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE.VALUE = 0;
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD_TYPE.RATE = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE = {};
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.SUM = 0;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.MAX = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.MIN = 2;
+BICst.TARGET_TYPE.CAL_VALUE.SUMMARY_TYPE.AVG = 3;
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE = {};
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE.ASC = 0;
+BICst.TARGET_TYPE.CAL_VALUE.RANK_TPYE.DESC = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUM_OF_ALL = 0;
+BICst.TARGET_TYPE.CAL_VALUE.PERIOD = 1;
+BICst.TARGET_TYPE.CAL_VALUE.SUM_OF_ABOVE = 2;
+BICst.TARGET_TYPE.CAL_VALUE.RANK = 3;
+BICst.TARGET_TYPE.CAL = {};
+BICst.TARGET_TYPE.CAL.FORMULA = 0;
+BICst.TARGET_TYPE.CAL.CONFIGURATION = 1;
+BICst.TARGET_TYPE.STRING = 1;
+BICst.TARGET_TYPE.NUMBER = 2;
+BICst.TARGET_TYPE.DATE = 3;
+BICst.TARGET_TYPE.COUNTER = 4;
+BICst.TARGET_TYPE.FORMULA = 5;
+BICst.TARGET_TYPE.YEAR_ON_YEAR_RATE = 6;
+BICst.TARGET_TYPE.MONTH_ON_MONTH_RATE = 7;
+BICst.TARGET_TYPE.YEAR_ON_YEAR_VALUE = 8;
+BICst.TARGET_TYPE.MONTH_ON_MONTH_VALUE = 9;
+BICst.TARGET_TYPE.SUM_OF_ABOVE = 10;
+BICst.TARGET_TYPE.SUM_OF_ABOVE_IN_GROUP = 11;
+BICst.TARGET_TYPE.SUM_OF_ALL = 12;
+BICst.TARGET_TYPE.SUM_OF_ALL_IN_GROUP = 13;
+BICst.TARGET_TYPE.RANK = 14;
+BICst.TARGET_TYPE.RANK_IN_GROUP = 15;
+BICst.DIMENSION_FILTER_DATE = {};
+BICst.DIMENSION_FILTER_DATE.BELONG_VALUE = 98;
+BICst.DIMENSION_FILTER_DATE.NOT_BELONG_VALUE = 99;
+BICst.DIMENSION_FILTER_DATE.IS_NULL = 100;
+BICst.DIMENSION_FILTER_DATE.NOT_NULL = 101;
+BICst.DIMENSION_FILTER_DATE.TOP_N = 102;
+BICst.DIMENSION_FILTER_DATE.BOTTOM_N = 103;
+BICst.DIMENSION_FILTER_DATE.CONTAIN = 104;
+BICst.DIMENSION_FILTER_DATE.NOT_CONTAIN = 105;
+BICst.DIMENSION_FILTER_DATE.BEGIN_WITH = 106;
+BICst.DIMENSION_FILTER_DATE.END_WITH = 107;
+BICst.FILTER_TYPE = {};
+BICst.FILTER_TYPE.AND = 80;
+BICst.FILTER_TYPE.OR = 81;
+BICst.FILTER_TYPE.FORMULA = 82;
+BICst.FILTER_TYPE.EMPTY_FORMULA = 90;
+BICst.FILTER_TYPE.EMPTY_CONDITION = 91;
+BICst.FILTER_TYPE.NUMBER_SUM = 83;
+BICst.FILTER_TYPE.NUMBER_AVG = 84;
+BICst.FILTER_TYPE.NUMBER_MAX = 85;
+BICst.FILTER_TYPE.NUMBER_MIN = 86;
+BICst.FILTER_TYPE.NUMBER_COUNT = 87;
+BICst.FILTER_TYPE.TREE_FILTER = 88;
+BICst.FILTER_TYPE.COLUMNFILTER = 89;
+BICst.FILTER_TYPE.DIMENSION_TARGET_VALUE_FILTER = 96;
+BICst.FILTER_TYPE.DIMENSION_SELF_FILTER = 97;
+BICst.FILTER_DATE = {};
+BICst.FILTER_DATE.BELONG_DATE_RANGE = 64;
+BICst.FILTER_DATE.BELONG_WIDGET_VALUE = 65;
+BICst.FILTER_DATE.NOT_BELONG_DATE_RANGE = 66;
+BICst.FILTER_DATE.NOT_BELONG_WIDGET_VALUE = 67;
+BICst.FILTER_DATE.MORE_THAN = 68;
+BICst.FILTER_DATE.LESS_THAN = 69;
+BICst.FILTER_DATE.EQUAL_TO = 70;
+BICst.FILTER_DATE.NOT_EQUAL_TO = 71;
+BICst.FILTER_DATE.IS_NULL = 72;
+BICst.FILTER_DATE.NOT_NULL = 73;
+BICst.FILTER_DATE.EARLY_THAN = 74;
+BICst.FILTER_DATE.LATER_THAN = 75;
+BICst.FILTER_DATE.CONTAINS = 76;
+BICst.FILTER_DATE.CONTAINS_DAY = 77;
+BICst.FILTER_DATE.DAY_EQUAL_TO = 78;
+BICst.FILTER_DATE.DAY_NOT_EQUAL_TO = 79;
+BICst.TARGET_FILTER_NUMBER = {};
+BICst.TARGET_FILTER_NUMBER.EQUAL_TO = 48;
+BICst.TARGET_FILTER_NUMBER.NOT_EQUAL_TO = 49;
+BICst.TARGET_FILTER_NUMBER.BELONG_VALUE = 50;
+BICst.TARGET_FILTER_NUMBER.BELONG_USER = 51;
+BICst.TARGET_FILTER_NUMBER.NOT_BELONG_VALUE = 52;
+BICst.TARGET_FILTER_NUMBER.NOT_BELONG_USER = 53;
+BICst.TARGET_FILTER_NUMBER.IS_NULL = 54;
+BICst.TARGET_FILTER_NUMBER.NOT_NULL = 55;
+BICst.TARGET_FILTER_NUMBER.CONTAINS = 56;
+BICst.TARGET_FILTER_NUMBER.NOT_CONTAINS = 57;
+BICst.TARGET_FILTER_NUMBER.LARGE_THAN_CAL_LINE = 58;
+BICst.TARGET_FILTER_NUMBER.LARGE_OR_EQUAL_CAL_LINE = 59;
+BICst.TARGET_FILTER_NUMBER.SMALL_THAN_CAL_LINE = 60;
+BICst.TARGET_FILTER_NUMBER.SMALL_OR_EQUAL_CAL_LINE = 61;
+BICst.TARGET_FILTER_NUMBER.TOP_N = 62;
+BICst.TARGET_FILTER_NUMBER.BOTTOM_N = 63;
+BICst.TARGET_FILTER_STRING = {};
+BICst.TARGET_FILTER_STRING.BELONG_VALUE = 32;
+BICst.TARGET_FILTER_STRING.BELONG_USER = 33;
+BICst.TARGET_FILTER_STRING.NOT_BELONG_VALUE = 34;
+BICst.TARGET_FILTER_STRING.NOT_BELONG_USER = 35;
+BICst.TARGET_FILTER_STRING.CONTAIN = 36;
+BICst.TARGET_FILTER_STRING.NOT_CONTAIN = 37;
+BICst.TARGET_FILTER_STRING.IS_NULL = 38;
+BICst.TARGET_FILTER_STRING.NOT_NULL = 39;
+BICst.TARGET_FILTER_STRING.BEGIN_WITH = 40;
+BICst.TARGET_FILTER_STRING.END_WITH = 41;
+BICst.TARGET_FILTER_STRING.NOT_BEGIN_WITH = 42;
+BICst.TARGET_FILTER_STRING.NOT_END_WITH = 43;
+BICst.TARGET_FILTER_STRING.VAGUE_CONTAIN = 46;
+BICst.TARGET_FILTER_STRING.NOT_VAGUE_CONTAIN = 47;
+BICst.DIMENSION_FILTER_NUMBER = {};
+BICst.DIMENSION_FILTER_NUMBER.BELONG_VALUE = 16;
+BICst.DIMENSION_FILTER_NUMBER.BELONG_USER = 17;
+BICst.DIMENSION_FILTER_NUMBER.NOT_BELONG_VALUE = 18;
+BICst.DIMENSION_FILTER_NUMBER.NOT_BELONG_USER = 19;
+BICst.DIMENSION_FILTER_NUMBER.MORE_THAN_AVG = 20;
+BICst.DIMENSION_FILTER_NUMBER.LESS_THAN_AVG = 21;
+BICst.DIMENSION_FILTER_NUMBER.IS_NULL = 22;
+BICst.DIMENSION_FILTER_NUMBER.NOT_NULL = 23;
+BICst.DIMENSION_FILTER_NUMBER.TOP_N = 24;
+BICst.DIMENSION_FILTER_NUMBER.BOTTOM_N = 25;
+BICst.DIMENSION_FILTER_STRING = {};
+BICst.DIMENSION_FILTER_STRING.BELONG_VALUE = 0;
+BICst.DIMENSION_FILTER_STRING.BELONG_USER = 1;
+BICst.DIMENSION_FILTER_STRING.NOT_BELONG_VALUE = 2;
+BICst.DIMENSION_FILTER_STRING.NOT_BELONG_USER = 3;
+BICst.DIMENSION_FILTER_STRING.CONTAIN = 4;
+BICst.DIMENSION_FILTER_STRING.NOT_CONTAIN = 5;
+BICst.DIMENSION_FILTER_STRING.IS_NULL = 6;
+BICst.DIMENSION_FILTER_STRING.NOT_NULL = 7;
+BICst.DIMENSION_FILTER_STRING.BEGIN_WITH = 8;
+BICst.DIMENSION_FILTER_STRING.END_WITH = 9;
+BICst.DIMENSION_FILTER_STRING.TOP_N = 10;
+BICst.DIMENSION_FILTER_STRING.BOTTOM_N = 11;
+BICst.DIMENSION_FILTER_STRING.NOT_BEGIN_WITH = 12;
+BICst.DIMENSION_FILTER_STRING.NOT_END_WITH = 13;
+BICst.DIMENSION_FILTER_STRING.VAGUE_CONTAIN = 14;
+BICst.DIMENSION_FILTER_STRING.NOT_VAGUE_CONTAIN = 15;
+BICst.GROUP = {};
+BICst.GROUP.NO_GROUP = 0;
+BICst.GROUP.AUTO_GROUP = 3;
+BICst.GROUP.CUSTOM_GROUP = 4;
+BICst.GROUP.CUSTOM_NUMBER_GROUP = 5;
+BICst.GROUP.Y = 6;
+BICst.GROUP.S = 7;
+BICst.GROUP.M = 8;
+BICst.GROUP.W = 9;
+BICst.GROUP.YMD = 10;
+BICst.GROUP.YD = 11;
+BICst.GROUP.MD = 12;
+BICst.GROUP.YMDHMS = 13;
+BICst.GROUP.ID_GROUP = 14;
+BICst.GROUP.HOUR = 15;
+BICst.GROUP.MINUTE = 16;
+BICst.GROUP.SECOND = 17;
+BICst.GROUP.WEEK_COUNT = 18;
+BICst.GROUP.D = 19;
+BICst.GROUP.YM = 20;
+BICst.GROUP.YW = 21;
+BICst.GROUP.YMDH = 22;
+BICst.GROUP.YMDHM = 23;
+BICst.GROUP.YS = 24;
+BICst.SUMMARY_TYPE = {};
+BICst.SUMMARY_TYPE.SUM = 0;
+BICst.SUMMARY_TYPE.MAX = 1;
+BICst.SUMMARY_TYPE.MIN = 2;
+BICst.SUMMARY_TYPE.AVG = 3;
+BICst.SUMMARY_TYPE.COUNT = 4;
+BICst.SUMMARY_TYPE.APPEND = 5;
+BICst.SUMMARY_TYPE.RECORD_COUNT = 6;
+BICst.BI_REPORT = {};
+BICst.BI_REPORT.NULL = 0;
+BICst.BI_REPORT.SUBMITED = 1;
+BICst.BI_REPORT.PUBLISHED = 2;
+BICst.VERSION = "4.0.2";
+BICst.SYSTEM_TIME = "__system_time-3e1d05defe78__";
+
+BICst.ETL_ADD_COLUMN_TYPE = {};
+BICst.ETL_ADD_COLUMN_TYPE.FORMULA = "formula";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_DIFF = "date_diff";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_YEAR = "date_year";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_SEASON = "date_season";
+BICst.ETL_ADD_COLUMN_TYPE.DATE_MONTH = "date_month";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_CPP = "expr_same_period";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_LP = "expr_last_period";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_CPP_PERCENT = "expr_same_period_percent";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_LP_PERCENT = "expr_last_period_percent";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_SUM = "expr_sum";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_ACC = "expr_acc";
+BICst.ETL_ADD_COLUMN_TYPE.EXPR_RANK = "expr_rank";
+BICst.ETL_ADD_COLUMN_TYPE.GROUP = "group_value";
+BICst.ETL_ADD_COLUMN_TYPE.SINGLE_VALUE = "single_value";
+BICst.ETL_ADD_COLUMN_TYPE.VALUE_CONVERT = "value_convert";
+BICst.JSON_KEYS = {};
+BICst.JSON_KEYS.STATISTIC_ELEMENT = "_src";
+BICst.JSON_KEYS.FILED_MAX_VALUE = "max";
+BICst.JSON_KEYS.FIELD_MIN_VALUE = "min";
+BICst.JSON_KEYS.FILTER_VALUE = "filter_value";
+BICst.JSON_KEYS.FILTER_CONDITION = "condition";
+BICst.JSON_KEYS.FILTER_AND_OR = "andor";
+BICst.JSON_KEYS.FILTER_TYPE = "filter_type";
+BICst.JSON_KEYS.FIELD_ID = "field_id";
+BICst.JSON_KEYS.FIELD_TYPE = "field_type";
+BICst.JSON_KEYS.FIELD_VALUE = "field_value";
+BICst.JSON_KEYS.FIELD_NAME = "field_name";
+BICst.JSON_KEYS.TYPE = "type";
+BICst.JSON_KEYS.VALUE = "value";
+BICst.JSON_KEYS.EXPANDER = "expander";
+BICst.JSON_KEYS.EXPANDER_X = "x";
+BICst.JSON_KEYS.EXPANDER_Y = "y";
+BICst.JSON_KEYS.CLICKEDVALUE = "clickedvalue";
+BICst.JSON_KEYS.SETTTINGS = "settings";
+BICst.JSON_KEYS.ID = "id";
+BICst.JSON_KEYS.TABLES = "tables";
+BICst.JSON_KEYS.TABLE = "table";
+BICst.JSON_KEYS.FIELDS = "fields";
+BICst.JSON_KEYS.FIELD = "field";
+BICst.JSON_KEYS.ETL_TYPE = "etl_type";
+BICst.JSON_KEYS.ETL_VALUE = "etl_value";
+BICst.JSON_KEYS.TABLE_TYPE = "table_type";
+BICst.JSON_KEYS.HAS_NEXT = "hasNext";
+BICst.JSON_KEYS.CONNECTION_NAME = "connection_name";
+BICst.JSON_KEYS.TABLE_NAME = "table_name";
+BICst.JSON_KEYS.TRAN_NAME = "tran_name";
+BICst.JSON_KEYS.TABLE_TRAN_NAME = "table_tran_name";
+BICst.JSON_KEYS.FIELD_TRAN_NAME = "field_tran_name";
+BICst.JSON_KEYS.GROUP_NAME = "group_name";
+BICst.JSON_KEYS.PACKAGE_NAME = "package_name";
+BICst.JSON_KEYS.RELATIONS = "relations";
+BICst.JSON_KEYS.TRANSLATIONS = "translations";
+BICst.JSON_KEYS.UPDATESETTING = "update_setting";
+BICst.JSON_KEYS.PACKAGE_ID = "package_id";
+BICst.JSON_KEYS.CONNECTION_SET = "connectionSet";
+BICst.JSON_KEYS.PRIMARY_KEY_MAP = "primKeyMap";
+BICst.JSON_KEYS.FOREIGN_KEY_MAP = "foreignKeyMap";
+
+BICst.DATA_CONFIG_DESIGN = {};
+BICst.DATA_CONFIG_DESIGN.NO = 0;
+BICst.DATA_CONFIG_DESIGN.YES = 1;
+BICst.DATA_CONFIG_AUTHORITY = {};
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER = {};
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.NODE = "__package_manager_node__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.PAGE = "__package_manager_page__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.SERVER_CONNECTION = "__package_server_connection__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_MANAGER.DATA_CONNECTION = "__package_data_connection__";
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION = {};
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION.NODE = "__data_connection_node__";
+BICst.DATA_CONFIG_AUTHORITY.DATA_CONNECTION.PAGE = "__data_connection_page__";
+BICst.DATA_CONFIG_AUTHORITY.MULTI_PATH_SETTING = "__multi_path_setting__";
+BICst.DATA_CONFIG_AUTHORITY.PACKAGE_AUTHORITY = "__package_authority__";
+BICst.DATA_CONFIG_AUTHORITY.FINE_INDEX_UPDATE = "__fine_index_update__";
+BICst.GLOBAL_UPDATE_TYPE = {};
+BICst.GLOBAL_UPDATE_TYPE.PART_UPDATE = "_part_update_";
+BICst.GLOBAL_UPDATE_TYPE.COMPLETE_UPDATE = "_complete_update_";
+BICst.GLOBAL_UPDATE_TYPE.META_UPDATE = "_meta_update_";
+BICst.CUBE_UPDATE_TYPE = {};
+BICst.CUBE_UPDATE_TYPE.GLOBAL_UPDATE = "__global_update__";
+BICst.CUBE_UPDATE_TYPE.SINGLETABLE_UPDATE = "__singleTable_update__";
+BICst.SINGLE_TABLE_UPDATE = {};
+BICst.SINGLE_TABLE_UPDATE.TOGETHER = 0;
+BICst.SINGLE_TABLE_UPDATE.NEVER = 1;
+BICst.SINGLE_TABLE_UPDATE_TYPE = {};
+BICst.SINGLE_TABLE_UPDATE_TYPE.ALL = 0;
+BICst.SINGLE_TABLE_UPDATE_TYPE.PART = 1;
+BICst.SINGLE_TABLE_UPDATE_TYPE.NEVER = 2;
+BICst.UPDATE_FREQUENCY = {};
+BICst.UPDATE_FREQUENCY.EVER_DAY = 0;
+BICst.UPDATE_FREQUENCY.EVER_SUNDAY = 1;
+BICst.UPDATE_FREQUENCY.EVER_MONDAY = 2;
+BICst.UPDATE_FREQUENCY.EVER_TUESDAY = 3;
+BICst.UPDATE_FREQUENCY.EVER_WEDNESDAY = 4;
+BICst.UPDATE_FREQUENCY.EVER_THURSDAY = 5;
+BICst.UPDATE_FREQUENCY.EVER_FRIDAY = 6;
+BICst.UPDATE_FREQUENCY.EVER_SATURDAY = 7;
+BICst.UPDATE_FREQUENCY.EVER_MONTH = 10;
+BICst.REQ_DATA_TYPE = {};
+BICst.REQ_DATA_TYPE.REQ_GET_ALL_DATA = -1;
+BICst.REQ_DATA_TYPE.REQ_GET_DATA_LENGTH = 0;
+BICst.TRANS_TYPE = {};
+BICst.TRANS_TYPE.READ_FROM_DB = "db";
+BICst.TRANS_TYPE.READ_FROM_TABLEDATA = "tabledata";
+BICst.TRANS_TYPE.CHOOSE = "choose";
+BICst.CONNECTION = {};
+BICst.CONNECTION.ETL_CONNECTION = "__FR_BI_ETL__";
+BICst.CONNECTION.SERVER_CONNECTION = "__FR_BI_SERVER__";
+BICst.CONNECTION.SQL_CONNECTION = "__FR_BI_SQL__";
+BICst.CONNECTION.EXCEL_CONNECTION = "__FR_BI_EXCEL__";
+BICst.COLUMN = {};
+BICst.COLUMN.NUMBER = 32;
+BICst.COLUMN.STRING = 16;
+BICst.COLUMN.DATE = 48;
+BICst.COLUMN.COUNTER = 64;
+BICst.COLUMN.ROW = 80;
+BICst.CLASS = {};
+BICst.CLASS.INTEGER = 0;
+BICst.CLASS.LONG = 1;
+BICst.CLASS.DOUBLE = 2;
+BICst.CLASS.FLOAT = 3;
+BICst.CLASS.DATE = 4;
+BICst.CLASS.STRING = 5;
+BICst.CLASS.BOOLEAN = 6;
+BICst.CLASS.TIMESTAMP = 7;
+BICst.CLASS.DECIMAL = 8;
+BICst.CLASS.TIME = 9;
+BICst.CLASS.BYTE = 10;
+BICst.CLASS.ROW = 16;
+BICst.SYSTEM_USER_NAME = "__system_user_name__";
+BICst.LAST_UPDATE_TIME = "__last_update_time__";
+BICst.CURRENT_UPDATE_TIME = "__current_update_time__";
+
+BICst.FUNCTION = {};
+BICst.FUNCTION.TEXT = 1;
+BICst.FUNCTION.MATH = 2;
+BICst.FUNCTION.DATE = 3;
+BICst.FUNCTION.ARRAY = 4;
+BICst.FUNCTION.LOGIC = 5;
+BICst.FUNCTION.OTHER = 6;
\ No newline at end of file
diff --git a/src/less/base/third/ztree/zTreeStyle.less b/src/less/base/third/ztree/zTreeStyle.less
index 1ceeca639..f6edbb45c 100644
--- a/src/less/base/third/ztree/zTreeStyle.less
+++ b/src/less/base/third/ztree/zTreeStyle.less
@@ -12,7 +12,7 @@ website:	http://code.google.com/p/jquerytree/
 .ztree {margin:0; padding:5px; color:#333}
 .ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0}
 .ztree li ul{ margin:0; padding:0 0 0 18px}
-.ztree li ul.line{ background:url(${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-1.png) 0 0 repeat-y;}
+.ztree li ul.line{ background:url(icon/tree-vertical-line-1.png) 0 0 repeat-y;}
 
 .ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:24px; color:#333; background-color: transparent;
   text-decoration:none; vertical-align:top; display: inline-block}
@@ -32,29 +32,29 @@ website:	http://code.google.com/p/jquerytree/
 
 .ztree li span.button.chk {width:16px; height:16px; margin:0 3px 0 0; cursor: auto}
 .ztree li span.button.chk.checkbox_false_full {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png");
+  background-image:url("icon/check-box-normal.png");
 }
 .ztree li span.button.chk.checkbox_false_full_focus {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-normal.png");
+  background-image:url("icon/check-box-normal.png");
 }
 .ztree li span.button.chk.checkbox_false_part {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image:url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_false_part_focus {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image:url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}
 .ztree li span.button.chk.checkbox_true_full {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png");
+  background-image:url("icon/check-box-active.png");
 }
 .ztree li span.button.chk.checkbox_true_full_focus {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/check-box-active.png");
+  background-image:url("icon/check-box-active.png");
 }
 .ztree li span.button.chk.checkbox_true_part {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image:url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_true_part_focus {
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/half_selected.png");
+  background-image:url("icon/half_selected.png");
 }
 .ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}
 .ztree li span.button.chk.radio_false_full {background-position:-28px 0}
@@ -70,40 +70,40 @@ website:	http://code.google.com/p/jquerytree/
 
 .ztree li span.button.switch {width:25px; height:25px}
 .ztree li span.button.root_open{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-1.png");
+  background-image:url("icon/tree-expand-1.png");
 }
 .ztree li span.button.root_close{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-1.png");
+  background-image:url("icon/tree-collapse-1.png");
 }
 .ztree li span.button.roots_open{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-2.png");
+  background-image:url("icon/tree-expand-2.png");
 }
 .ztree li span.button.roots_close{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-2.png");
+  background-image:url("icon/tree-collapse-2.png");
 }
 .ztree li span.button.center_open{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-3.png");
+  background-image:url("icon/tree-expand-3.png");
 }
 .ztree li span.button.center_close{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-3.png");
+  background-image:url("icon/tree-collapse-3.png");
 }
 .ztree li span.button.bottom_open{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-expand-4.png");
+  background-image:url("icon/tree-expand-4.png");
 }
 .ztree li span.button.bottom_close{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-collapse-4.png");
+  background-image:url("icon/tree-collapse-4.png");
 }
 .ztree li span.button.noline_open{background-position:-92px -72px}
 .ztree li span.button.noline_close{background-position:-74px -72px}
 .ztree li span.button.root_docu{ background:none;}
 .ztree li span.button.roots_docu{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-2.png");
+  background-image:url("icon/tree-vertical-line-2.png");
 }
 .ztree li span.button.center_docu{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-3.png");
+  background-image:url("icon/tree-vertical-line-3.png");
 }
 .ztree li span.button.bottom_docu{
-  background-image:url("${servletURL}?op=resource&resource=/com/fr/bi/web/images/icon/tree-vertical-line-4.png");
+  background-image:url("icon/tree-vertical-line-4.png");
 }
 .ztree li span.button.noline_docu{ background:none;}
 
diff --git a/src/less/core/app.less b/src/less/core/app.less
index a27810ede..5b683504e 100644
--- a/src/less/core/app.less
+++ b/src/less/core/app.less
@@ -2,7 +2,7 @@
 
 @font-face {
   font-family: 'bi';
-  src: url('@{webUrl}resources/fonts/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('@{webUrl}resources/fonts/iconfont.woff') format('woff'), /* chrome、firefox */ url('@{webUrl}resources/fonts/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('@{webUrl}resources/fonts/iconfont.svg#svgFontName') format('svg'); /*  iOS 4.1- */
+  src: url('@{webUrl}font/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('@{webUrl}font/iconfont.woff') format('woff'), /* chrome、firefox */ url('@{webUrl}font/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('@{webUrl}font/iconfont.svg#svgFontName') format('svg'); /*  iOS 4.1- */
 }
 
 .b-font {
diff --git a/src/less/lib/colors.less b/src/less/lib/colors.less
index f446f5000..97c56da69 100644
--- a/src/less/lib/colors.less
+++ b/src/less/lib/colors.less
@@ -140,4 +140,21 @@
 
 @color-login-info-fields-group-background: @background-color-light-blue;
 //mask颜色
-@color-bi-button-mask : @color-bi-background-black;
\ No newline at end of file
+@color-bi-button-mask : @color-bi-background-black;
+
+
+// 数据连接底色 10种 --start--
+@color-bi-data-link-button-color1: @data-link-color1;
+@color-bi-data-link-button-color2: @data-link-color2;
+@color-bi-data-link-button-color3: @data-link-color3;
+@color-bi-data-link-button-color4: @data-link-color4;
+@color-bi-data-link-button-color5: @data-link-color5;
+@color-bi-data-link-button-color6: @data-link-color6;
+@color-bi-data-link-button-color7: @data-link-color7;
+@color-bi-data-link-button-color8: @data-link-color8;
+@color-bi-data-link-button-color9: @data-link-color9;
+@color-bi-data-link-button-color10: @data-link-color10;
+// 数据连接底色 10种 --end--
+
+@color-bi-progress-text-bar-background: @border-color-light-green;
+@color-bi-progress-text-bar-processor: @border-color-success;
diff --git a/src/less/lib/constant.less b/src/less/lib/constant.less
index 7717ec145..5b5d2dd96 100644
--- a/src/less/lib/constant.less
+++ b/src/less/lib/constant.less
@@ -97,4 +97,15 @@
 @table-color-green: #daf3dc;
 @table-color-light-blue: #d6f7f0;
 @table-color-purple: #e8e6fe;
-@table-color-pink: #fee9e9;
\ No newline at end of file
+@table-color-pink: #fee9e9;
+
+@data-link-color1: #009de3;
+@data-link-color2: #4fc1e9;
+@data-link-color3: #48cfad;
+@data-link-color4: #57cb7c;
+@data-link-color5: #a0d468;
+@data-link-color6: #fbaf4f;
+@data-link-color7: #fc6e51;
+@data-link-color8: #ed5565;
+@data-link-color9: #ac92ec;
+@data-link-color10: #5d9cec;
\ No newline at end of file
diff --git a/src/less/var.less b/src/less/var.less
index fef2af92f..7d4d2b66e 100644
--- a/src/less/var.less
+++ b/src/less/var.less
@@ -1,8 +1,9 @@
-@webUrl: '${servletURL}?op=resource&resource=/com/fr/bi/web/';
-@imageUrl: '${servletURL}?op=resource&resource=/com/fr/bi/web/images/'; //图片的基本地址
+@webUrl: '';
+@imageUrl: ''; //图片的基本地址
 
 @cursor: '@{imageUrl}cursor/cursor_hand.cur';
 @dragCursor: '@{imageUrl}cursor/cursor_drag_hand.cur';
+@leftRightCursor:'@{imageUrl}cursor/cursor_left_right.cur';
 
 @zIndex-layer:    100000;
 @zIndex-floatbox: 1000000;
diff --git a/src/less/widget/arrangement/arrangement.block.less b/src/less/widget/arrangement/arrangement.block.less
new file mode 100644
index 000000000..c8ce41699
--- /dev/null
+++ b/src/less/widget/arrangement/arrangement.block.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-arrangement-block{
+  background:@color-bi-background-failure;
+  .opacity(0.8);
+}
\ No newline at end of file
diff --git a/src/less/widget/arrangement/arrangement.droppable.less b/src/less/widget/arrangement/arrangement.droppable.less
new file mode 100644
index 000000000..a286327a0
--- /dev/null
+++ b/src/less/widget/arrangement/arrangement.droppable.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-arrangement-droppable{
+  background:@color-bi-background-virtual-blue;
+  .opacity(0.8);
+  z-index: @zIndex-layer;
+}
\ No newline at end of file
diff --git a/src/less/widget/arrangement/arrangement.less b/src/less/widget/arrangement/arrangement.less
new file mode 100644
index 000000000..9653725ad
--- /dev/null
+++ b/src/less/widget/arrangement/arrangement.less
@@ -0,0 +1,29 @@
+@import "../../bibase";
+
+.bi-arrangement {
+  & .arrangement-helper {
+    border: 1px solid @color-bi-border-normal;
+    background: @color-bi-background-highlight;
+    z-index: @zIndex-tip;
+  }
+  & .arrangement-block {
+    z-index: @zIndex-tip;
+  }
+  & .arrangement-drop-container {
+    z-index: @zIndex-tip;
+    & .arrangement-drop-region {
+      overflow: hidden;
+    }
+    & .drop-devider{
+      z-index: @zIndex-tip + 1;
+      background: @color-bi-background-highlight;
+    }
+    & .top-left, & .top-right, & .bottom-left, & .bottom-right,
+    & .top-left-second, & .top-right-second, & .bottom-left-second, & .bottom-right-second,
+    & .top-center, & .bottom-center, & .left-center, & .right-center,
+    & .top-center-second, & .bottom-center-second, & .left-center-second, & .right-center-second {
+      z-index: @zIndex-tip + 1;
+      background: @color-bi-background-highlight;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/combo/iconcombo/combo.icon.less b/src/less/widget/base/combo/iconcombo/combo.icon.less
new file mode 100644
index 000000000..f656f1b6c
--- /dev/null
+++ b/src/less/widget/base/combo/iconcombo/combo.icon.less
@@ -0,0 +1,11 @@
+@import "../../../../bibase";
+
+.bi-icon-combo{
+  &.bi-combo-popup{
+    & .bi-icon-combo-trigger{
+      & .b-font:before{
+        color: @color-bi-text-highlight;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.adapt.less b/src/less/widget/base/editor/editor.adapt.less
new file mode 100644
index 000000000..b7074b700
--- /dev/null
+++ b/src/less/widget/base/editor/editor.adapt.less
@@ -0,0 +1,7 @@
+@import "../../../bibase";
+
+.bi-adapt-editor{
+  .adapt-editor-text{
+    font-size: @font-size-14;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.search.less b/src/less/widget/base/editor/editor.search.less
new file mode 100644
index 000000000..34c414543
--- /dev/null
+++ b/src/less/widget/base/editor/editor.search.less
@@ -0,0 +1,11 @@
+@import "../../../bibase";
+/*************BI.SearchEditor******************/
+.bi-search-editor {
+  border: 1px solid @color-bi-border-normal;
+  & .close-font{
+    font-size: 20px;
+  }
+  & .search-font{
+    font-size: 20px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.search.small.less b/src/less/widget/base/editor/editor.search.small.less
new file mode 100644
index 000000000..09736f98f
--- /dev/null
+++ b/src/less/widget/base/editor/editor.search.small.less
@@ -0,0 +1,19 @@
+@import "../../../bibase";
+/*************BI.SearchEditor******************/
+.bi-small-search-editor {
+  & .bi-editor {
+    font-size: @font-size-12;
+    & .bi-input{
+      font-size: @font-size-12;
+    }
+    & .bi-label{
+      font-size: @font-size-12;
+    }
+  }
+  & .close-font{
+    font-size: 18px;
+  }
+  & .search-font{
+    font-size: 18px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.sign.initial.less b/src/less/widget/base/editor/editor.sign.initial.less
new file mode 100644
index 000000000..4d3d7ea21
--- /dev/null
+++ b/src/less/widget/base/editor/editor.sign.initial.less
@@ -0,0 +1,7 @@
+@import "../../../bibase";
+
+.bi-sign-initial-editor{
+  .sign-initial-editor-text{
+    font-size: @font-size-14;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.sign.style.less b/src/less/widget/base/editor/editor.sign.style.less
new file mode 100644
index 000000000..3d4682625
--- /dev/null
+++ b/src/less/widget/base/editor/editor.sign.style.less
@@ -0,0 +1,13 @@
+@import "../../../bibase";
+
+.bi-sign-style-editor{
+  & .sign-style-editor-text{
+    max-width: 100%;
+    font-size: @font-size-12;
+  }
+  & .sign-style-editor-tip{
+    max-width: 100%;
+    font-size: @font-size-12;
+    color: @font-color-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.text.less b/src/less/widget/base/editor/editor.text.less
new file mode 100644
index 000000000..27d231611
--- /dev/null
+++ b/src/less/widget/base/editor/editor.text.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-text-editor{
+  border: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/base/editor/editor.text.small.less b/src/less/widget/base/editor/editor.text.small.less
new file mode 100644
index 000000000..679652bc3
--- /dev/null
+++ b/src/less/widget/base/editor/editor.text.small.less
@@ -0,0 +1,6 @@
+@import "../../../bibase";
+/*************BI.SearchEditor******************/
+.bi-small-text-editor {
+  & .bi-editor {
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/mask/loading.mask.less b/src/less/widget/base/mask/loading.mask.less
new file mode 100644
index 000000000..f31fced00
--- /dev/null
+++ b/src/less/widget/base/mask/loading.mask.less
@@ -0,0 +1,13 @@
+@import "../../../bibase";
+
+.bi-loading-main-background {
+  background-color: @color-bi-background-default;
+  .opacity(0.7);
+}
+
+.bi-loading-mask-content {
+  & .loading-bar-label {
+    font-size: 20px;
+    color: @color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/segment/button.line.segment.less b/src/less/widget/base/segment/button.line.segment.less
new file mode 100644
index 000000000..094bf6219
--- /dev/null
+++ b/src/less/widget/base/segment/button.line.segment.less
@@ -0,0 +1,13 @@
+@import "../../../bibase";
+
+.bi-line-segment-button{
+  &.active {
+    & .line-segment-button-line {
+      background: @color-bi-background-highlight;
+    }
+  }
+  &.disabled, &.disabled:hover, &.disabled:active {
+    color: @color-bi-text-black;
+    background: @color-bi-background-default;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/segment/segment.line.less b/src/less/widget/base/segment/segment.line.less
new file mode 100644
index 000000000..8e7d6f51d
--- /dev/null
+++ b/src/less/widget/base/segment/segment.line.less
@@ -0,0 +1,6 @@
+@import "../../../bibase";
+
+
+.bi-line-segment{
+  border-bottom: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/base/tip/tip.helper.less b/src/less/widget/base/tip/tip.helper.less
new file mode 100644
index 000000000..5d206f17a
--- /dev/null
+++ b/src/less/widget/base/tip/tip.helper.less
@@ -0,0 +1,16 @@
+@import "../../../bibase";
+.bi-helper{
+  background-color: @background-color-highlight;
+  font-size: 13px;
+  color:@color-bi-text;
+  cursor: url('@{dragCursor}'), auto;
+  opacity: 0.7;
+  &.dragging-modify{
+    background: none;
+    & .helper-warning{
+      color: @color-bi-text-black;
+      border: 1px solid @color-bi-border-failure;
+      .border-radius(2px);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/toolbar/toolbar.progress.bar.less b/src/less/widget/base/toolbar/toolbar.progress.bar.less
new file mode 100644
index 000000000..d80d15d51
--- /dev/null
+++ b/src/less/widget/base/toolbar/toolbar.progress.bar.less
@@ -0,0 +1,6 @@
+@import "../../../bibase";
+
+.bi-progress-bar-bar{
+  background: @color-bi-background-light;
+  .border-radius(20px);
+}
\ No newline at end of file
diff --git a/src/less/widget/base/toolbar/toolbar.progress.less b/src/less/widget/base/toolbar/toolbar.progress.less
new file mode 100644
index 000000000..74797951b
--- /dev/null
+++ b/src/less/widget/base/toolbar/toolbar.progress.less
@@ -0,0 +1,12 @@
+@import "../../../bibase";
+
+.bi-progress-bar{
+  & .progress-bar-label{
+    font-weight: bold;
+    font-family: "微软雅黑";
+    color: @color-bi-text-highlight;
+    &.success{
+      color: @color-bi-text-success;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/base/toolbar/toolbar.progress.processor.less b/src/less/widget/base/toolbar/toolbar.progress.processor.less
new file mode 100644
index 000000000..65da00a28
--- /dev/null
+++ b/src/less/widget/base/toolbar/toolbar.progress.processor.less
@@ -0,0 +1,10 @@
+@import "../../../bibase";
+
+.bi-progress-bar-processor{
+  background: @color-bi-background-highlight;
+  .border-radius(20px);
+  .overflow-hidden();
+  &.success{
+    background: @color-bi-background-success;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/colorchooser/colorchooser.popup.less b/src/less/widget/colorchooser/colorchooser.popup.less
new file mode 100644
index 000000000..a51528852
--- /dev/null
+++ b/src/less/widget/colorchooser/colorchooser.popup.less
@@ -0,0 +1,14 @@
+@import "../../bibase";
+
+.bi-color-chooser-popup{
+  & .color-chooser-popup-title{
+    background: @color-bi-background-gray;
+    border-bottom: 1px solid @color-bi-split-dark;
+  }
+  & .color-chooser-popup-more{
+    background: @color-bi-background-gray;
+    &:hover{
+      background: @color-bi-background-dark;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/colorchooser/colorchooser.trigger.less b/src/less/widget/colorchooser/colorchooser.trigger.less
new file mode 100644
index 000000000..fa74a4e63
--- /dev/null
+++ b/src/less/widget/colorchooser/colorchooser.trigger.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-color-chooser-trigger{
+  background: @color-bi-background-default;
+  .border-radius(2px);
+  .box-shadow(0px,0px,2px,1px, @color-bi-background-dark, inset);
+}
\ No newline at end of file
diff --git a/src/less/widget/copy2group/button.add.copy2group.less b/src/less/widget/copy2group/button.add.copy2group.less
new file mode 100644
index 000000000..c74eaf1be
--- /dev/null
+++ b/src/less/widget/copy2group/button.add.copy2group.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-copy2group-add-button{
+  .border-radius(2px);
+  background: @color-bi-tooltip-success-background;
+}
\ No newline at end of file
diff --git a/src/less/widget/copy2group/combo.copy2group.less b/src/less/widget/copy2group/combo.copy2group.less
new file mode 100644
index 000000000..5fbdca4ba
--- /dev/null
+++ b/src/less/widget/copy2group/combo.copy2group.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.copy2_group_search_pane{
+  background: @color-bi-background-default;
+}
\ No newline at end of file
diff --git a/src/less/widget/date/calendar/picker.date.less b/src/less/widget/date/calendar/picker.date.less
new file mode 100644
index 000000000..bcdf79a2d
--- /dev/null
+++ b/src/less/widget/date/calendar/picker.date.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-date-picker{
+  background: @color-bi-background-gray;
+}
\ No newline at end of file
diff --git a/src/less/widget/date/trigger.date.less b/src/less/widget/date/trigger.date.less
new file mode 100644
index 000000000..0c889d3fb
--- /dev/null
+++ b/src/less/widget/date/trigger.date.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-date-trigger {
+  border: 1px solid @color-bi-border-normal;
+  .border-radius(2px);
+}
\ No newline at end of file
diff --git a/src/less/widget/downlist/combo.downlist.less b/src/less/widget/downlist/combo.downlist.less
new file mode 100644
index 000000000..726ffb663
--- /dev/null
+++ b/src/less/widget/downlist/combo.downlist.less
@@ -0,0 +1,23 @@
+@import "../../bibase";
+
+
+
+.bi-down-list-combo{
+  & .down-list-group{
+    &.bi-combo-hover{
+      & .bi-down-list-group-item{
+        &, & .b-font:before{
+          background-color: @color-bi-background-gray;
+        }
+        &:disabled, &.disabled{
+          &, & .b-font:before{
+            background-color: @color-bi-background-default
+          }
+        }
+      }
+    }
+  }
+  & .bi-down-list-spliter{
+    border-top: 1px solid @color-bi-split-light;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/downlist/popup.downlist.less b/src/less/widget/downlist/popup.downlist.less
new file mode 100644
index 000000000..78e10e04a
--- /dev/null
+++ b/src/less/widget/downlist/popup.downlist.less
@@ -0,0 +1,21 @@
+@import "../../bibase";
+
+.bi-down-list-popup {
+  & .bi-down-list-item {
+    &:hover, &.hover {
+      background-color: @color-bi-background-gray;
+    }
+    &.disabled {
+      &, &:hover, &:active {
+        background-color: @color-bi-background-default;
+      }
+    }
+    &:active {
+      color: @color-bi-text-highlight;
+      background-color: @color-bi-background-gray;
+    }
+    & .list-item-text {
+      max-width: 203px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.less b/src/less/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.less
new file mode 100644
index 000000000..8d167f444
--- /dev/null
+++ b/src/less/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.less
@@ -0,0 +1,13 @@
+@import "../../bibase";
+
+.bi-sheet-tab-dynamic-button {
+  background: @color-bi-background-light;
+  border-top: 1px solid @color-bi-border-normal;
+
+  & .bi-icon-button-scroll {
+    border:1px solid @background-color-light;
+    &:hover {
+      border-color: @color-bi-border-normal;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/exceltable/exceltable.cell.less b/src/less/widget/exceltable/exceltable.cell.less
new file mode 100644
index 000000000..d7aa69f77
--- /dev/null
+++ b/src/less/widget/exceltable/exceltable.cell.less
@@ -0,0 +1,4 @@
+@import "../../bibase";
+
+.bi-excel-table-cell {
+}
\ No newline at end of file
diff --git a/src/less/widget/exceltable/exceltable.header.cell.less b/src/less/widget/exceltable/exceltable.header.cell.less
new file mode 100644
index 000000000..470796711
--- /dev/null
+++ b/src/less/widget/exceltable/exceltable.header.cell.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-excel-table-header-cell {
+  font-weight: bold;
+  background-color: @color-bi-background-light;
+}
\ No newline at end of file
diff --git a/src/less/widget/exceltable/exceltable.less b/src/less/widget/exceltable/exceltable.less
new file mode 100644
index 000000000..00157e766
--- /dev/null
+++ b/src/less/widget/exceltable/exceltable.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-excel-table {
+  & > div.bottom-right > div > div > table {
+    border-right: 1px solid @color-bi-border-line;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/filemanager/filemanager.less b/src/less/widget/filemanager/filemanager.less
new file mode 100644
index 000000000..b2b135c70
--- /dev/null
+++ b/src/less/widget/filemanager/filemanager.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-file-manager{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/filemanager/items/item.file.filemanager.less b/src/less/widget/filemanager/items/item.file.filemanager.less
new file mode 100644
index 000000000..3eac6a1b3
--- /dev/null
+++ b/src/less/widget/filemanager/items/item.file.filemanager.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-file-manager-file-item{
+  border-bottom: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/filemanager/items/item.folder.filemanager.less b/src/less/widget/filemanager/items/item.folder.filemanager.less
new file mode 100644
index 000000000..dc38b2a1a
--- /dev/null
+++ b/src/less/widget/filemanager/items/item.folder.filemanager.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-file-manager-folder-item{
+  border-bottom: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/filemanager/nav/button/button.nav.filemanager.less b/src/less/widget/filemanager/nav/button/button.nav.filemanager.less
new file mode 100644
index 000000000..072a1c56d
--- /dev/null
+++ b/src/less/widget/filemanager/nav/button/button.nav.filemanager.less
@@ -0,0 +1,15 @@
+@import "../../../../bibase";
+
+.bi-file-manager-nav-button{
+  & .file-manager-nav-button-text{
+    max-width: 200px;
+    background: @background-color-default;
+    &.active{
+      background-color: @color-bi-background-gray;
+      color: @color-bi-text-gray;
+    }
+  }
+  & .file-manager-nav-button-triangle{
+    z-index: 1;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/filemanager/nav/nav.filemanager.less b/src/less/widget/filemanager/nav/nav.filemanager.less
new file mode 100644
index 000000000..5db4f1452
--- /dev/null
+++ b/src/less/widget/filemanager/nav/nav.filemanager.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-file-manager-nav{
+  border-left: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/filterpane/abstract.item.filter.less b/src/less/widget/filterpane/abstract.item.filter.less
new file mode 100644
index 000000000..f210ec3d7
--- /dev/null
+++ b/src/less/widget/filterpane/abstract.item.filter.less
@@ -0,0 +1,14 @@
+@import "../../bibase";
+
+.bi-filter-item {
+  //min-width: 470px;
+  border-right: 1px solid @color-bi-border-normal;
+  border-bottom: 1px solid @color-bi-border-normal;
+  & .filter-item-empty-item {
+    border-top: 1px solid @color-bi-border-normal;
+    & .empty-filter-item-leaf{
+      border: 1px dashed @color-bi-border-highlight;
+      background: @color-bi-background-success;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/filterpane/expander.filter.less b/src/less/widget/filterpane/expander.filter.less
new file mode 100644
index 000000000..80f3bfbad
--- /dev/null
+++ b/src/less/widget/filterpane/expander.filter.less
@@ -0,0 +1,23 @@
+@import "../../bibase";
+
+.bi-filter-expander {
+  min-width: 100%;
+  border-right: 0px;
+  border-bottom: 0px;
+  & > .filter-item-empty-item {
+    border-top: 0px;
+    border-right: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+  }
+  & .condition-and-or {
+
+  }
+  > table {
+    min-width: 100%;
+  }
+  > table > tbody > tr > td.first-element {
+    width: 20px;
+    border-right: 1px solid @color-bi-border-normal !important;
+    border-bottom: 1px solid @color-bi-border-normal !important;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/filterpane/pane.filter.less b/src/less/widget/filterpane/pane.filter.less
new file mode 100644
index 000000000..e27696207
--- /dev/null
+++ b/src/less/widget/filterpane/pane.filter.less
@@ -0,0 +1,12 @@
+@import "../../bibase";
+
+.bi-filter-pane {
+  min-width: 100%;
+  .border-radius(2px);
+  border-top: 1px solid @color-bi-border-normal;
+  border-left: 1px solid @color-bi-border-normal;
+  & .condition-container {
+    border-right: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/finetuningnumbereditor/finetuning.number.editor.less b/src/less/widget/finetuningnumbereditor/finetuning.number.editor.less
new file mode 100644
index 000000000..2f7905f81
--- /dev/null
+++ b/src/less/widget/finetuningnumbereditor/finetuning.number.editor.less
@@ -0,0 +1,13 @@
+@import "../../bibase";
+
+.bi-fine-tuning-number-editor {
+  border: 1px solid @border-color-normal;
+  .border-radius(2px);
+  & .top-button {
+    border-left: 1px solid @border-color-normal;
+    border-bottom: 1px solid @border-color-normal;
+  }
+  & .bottom-button {
+    border-left: 1px solid @border-color-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/editor.search.less b/src/less/widget/formula/editor.search.less
new file mode 100644
index 000000000..6b7e36d12
--- /dev/null
+++ b/src/less/widget/formula/editor.search.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-search-edit{
+  &{
+    border: 1px solid @color-bi-background-dark;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/group.symbol.less b/src/less/widget/formula/group.symbol.less
new file mode 100644
index 000000000..04c6e7c04
--- /dev/null
+++ b/src/less/widget/formula/group.symbol.less
@@ -0,0 +1,21 @@
+@import "../../bibase";
+
+.bi-formula-symbol-group{
+  & .symbol-button{
+    &:hover, &.hover, &:active, &.active{
+      color:@color-bi-text-highlight;
+      background-color:@color-bi-background-gray;
+      border:1px solid @color-bi-background-dark;
+    }
+    &{
+      color:@color-bi-text-highlight;
+      border:1px solid @color-bi-background-default;
+    }
+  }
+}
+
+.symbol-group-column{
+  &{
+    border:1px solid @color-bi-background-dark;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/insert.formula.less b/src/less/widget/formula/insert.formula.less
new file mode 100644
index 000000000..747603397
--- /dev/null
+++ b/src/less/widget/formula/insert.formula.less
@@ -0,0 +1,31 @@
+@import "../../bibase";
+
+.bi-formula-insert {
+  & .more-function-button {
+    & {
+      color: @color-bi-text-highlight
+    }
+  }
+  & .bi-formula-field-pane {
+    border-top: 1px solid @color-bi-border-normal;
+    border-left: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+  }
+  & .bi-formula-editor {
+    border-left: 1px solid @color-bi-border-normal;
+    border-top: 1px solid @color-bi-border-normal;
+    border-right: 1px solid @color-bi-border-normal;
+
+  }
+  & .bi-water-mark {
+    font-size: 14px;
+  }
+
+  & .proxy_div {
+    font-size: 13px;
+    background-color: @color-bi-background-highlight;
+    color: @color-bi-text;
+    opacity: 0.7;
+    cursor: pointer;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/item.button.text.treeleaf.less b/src/less/widget/formula/item.button.text.treeleaf.less
new file mode 100644
index 000000000..7542785bd
--- /dev/null
+++ b/src/less/widget/formula/item.button.text.treeleaf.less
@@ -0,0 +1,19 @@
+@import "../../bibase";
+
+.bi-button-text-tree-item{
+  &:hover,&.hover{
+    background-color: @color-bi-background-gray;
+  }
+  &.active{
+    color: @color-bi-text-highlight;
+    background-color: @color-bi-background-gray;
+  }
+  &.disabled{
+    &, &:hover, &:active{
+      background-color: @color-bi-background-default;
+    }
+  }
+  & .formula-function-insert-button{
+    color:@color-bi-text-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/pane.function.less b/src/less/widget/formula/pane.function.less
new file mode 100644
index 000000000..8ffc6d14f
--- /dev/null
+++ b/src/less/widget/formula/pane.function.less
@@ -0,0 +1,20 @@
+@import "../../bibase";
+
+.bi-formula-function-pane {
+  & .style-inner {
+    & {
+      border-left: 1px solid @color-bi-background-dark;
+      border-top: 1px solid @color-bi-background-dark;
+    }
+  }
+  & .style-top {
+    border-top: 1px solid @color-bi-background-dark;
+  }
+  & .style-left {
+    border-left: 1px solid @color-bi-background-dark;
+  }
+  &{
+    background-color: @color-bi-background-default;
+  }
+
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/tree.fieldname.less b/src/less/widget/formula/tree.fieldname.less
new file mode 100644
index 000000000..f2f927760
--- /dev/null
+++ b/src/less/widget/formula/tree.fieldname.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-formula-field-tree{
+  background-color: @color-bi-background-gray;
+}
\ No newline at end of file
diff --git a/src/less/widget/formula/tree.function.less b/src/less/widget/formula/tree.function.less
new file mode 100644
index 000000000..cd4acf7ab
--- /dev/null
+++ b/src/less/widget/formula/tree.function.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-formula-function-tree{
+  background-color: @color-bi-background-default;
+}
\ No newline at end of file
diff --git a/src/less/widget/image/button/href/image.button.href.less b/src/less/widget/image/button/href/image.button.href.less
new file mode 100644
index 000000000..c21685e57
--- /dev/null
+++ b/src/less/widget/image/button/href/image.button.href.less
@@ -0,0 +1,7 @@
+@import "../../../../bibase";
+.bi-image-button-href {
+  & .image-button-href-icon-button{
+    z-index: 1;
+    font-size: @font-size-16
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/image/button/size/image.button.size.less b/src/less/widget/image/button/size/image.button.size.less
new file mode 100644
index 000000000..86230484d
--- /dev/null
+++ b/src/less/widget/image/button/size/image.button.size.less
@@ -0,0 +1,7 @@
+@import "../../../../bibase";
+.bi-image-button-size{
+  & .image-button-size-button-group{
+    font-size: @font-size-12;
+    color: @font-color-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/image/button/upload.less b/src/less/widget/image/button/upload.less
new file mode 100644
index 000000000..b32eb7edc
--- /dev/null
+++ b/src/less/widget/image/button/upload.less
@@ -0,0 +1 @@
+@import "../../../bibase";
\ No newline at end of file
diff --git a/src/less/widget/image/uploadimage.less b/src/less/widget/image/uploadimage.less
new file mode 100644
index 000000000..0f56fde36
--- /dev/null
+++ b/src/less/widget/image/uploadimage.less
@@ -0,0 +1,18 @@
+@import "../../bibase";
+.bi-upload-image{
+  & .upload-image-text-button-label{
+    font-size: @font-size-14;
+    color:  @font-color-tips
+  }
+
+  & .upload-image-icon-button{
+    z-index: 1;
+    font-size: @font-size-16;
+    background-color: @color-bi-background-default;
+  }
+
+  & .upload-image-delete-label{
+    font-size: @font-size-14;
+    color: @font-color-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/interactivearrangement/interactivearrangement.less b/src/less/widget/interactivearrangement/interactivearrangement.less
new file mode 100644
index 000000000..7db22b8f0
--- /dev/null
+++ b/src/less/widget/interactivearrangement/interactivearrangement.less
@@ -0,0 +1,11 @@
+@import "../../bibase";
+
+.bi-interactive-arrangement {
+  & .interactive-arrangement-dragtag-line {
+    z-index: @zIndex-tip;
+    background-color: @color-bi-text-redmark;
+  }
+  & .interactive-arrangement-dragtag-icon {
+    z-index: @zIndex-tip;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/listlabel/listlabel.less b/src/less/widget/listlabel/listlabel.less
new file mode 100644
index 000000000..f799827d8
--- /dev/null
+++ b/src/less/widget/listlabel/listlabel.less
@@ -0,0 +1,10 @@
+@import "../../bibase";
+
+.bi-list-label {
+  font-size: @font-size-14;
+  .list-label-button {
+    &:hover {
+      color: @font-color-warning
+    }
+  }
+}
diff --git a/src/less/widget/month/combo.month.less b/src/less/widget/month/combo.month.less
new file mode 100644
index 000000000..f206adfc5
--- /dev/null
+++ b/src/less/widget/month/combo.month.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-month-combo{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/month/popup.month.less b/src/less/widget/month/popup.month.less
new file mode 100644
index 000000000..9170555b9
--- /dev/null
+++ b/src/less/widget/month/popup.month.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-month-popup{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/month/trigger.month.less b/src/less/widget/month/trigger.month.less
new file mode 100644
index 000000000..883c3248f
--- /dev/null
+++ b/src/less/widget/month/trigger.month.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+.bi-month-trigger{
+  border: 1px solid @color-bi-border-normal;
+  .border-radius(2px);
+}
\ No newline at end of file
diff --git a/src/less/widget/move2group/button.add.move2group.less b/src/less/widget/move2group/button.add.move2group.less
new file mode 100644
index 000000000..5040d2185
--- /dev/null
+++ b/src/less/widget/move2group/button.add.move2group.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-move2group-add-button{
+  .border-radius(2px);
+  background: @color-bi-tooltip-success-background;
+}
\ No newline at end of file
diff --git a/src/less/widget/move2group/combo.move2group.less b/src/less/widget/move2group/combo.move2group.less
new file mode 100644
index 000000000..4d3716e06
--- /dev/null
+++ b/src/less/widget/move2group/combo.move2group.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.move2_group_search_pane{
+  background: @color-bi-background-default;
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.combo.less b/src/less/widget/multidate/multidate.combo.less
new file mode 100644
index 000000000..6beb54694
--- /dev/null
+++ b/src/less/widget/multidate/multidate.combo.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-multidate-combo{
+  .border-radius(2px);
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.day.less b/src/less/widget/multidate/multidate.day.less
new file mode 100644
index 000000000..e497d8949
--- /dev/null
+++ b/src/less/widget/multidate/multidate.day.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multidate-daycard{
+  & .bi-multidate-inner-label{
+    //font-size: @font-size-14;
+    color:@color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.month.less b/src/less/widget/multidate/multidate.month.less
new file mode 100644
index 000000000..4478abdd5
--- /dev/null
+++ b/src/less/widget/multidate/multidate.month.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multidate-monthcard{
+  & .bi-multidate-inner-label{
+    //font-size:@font-size-14;
+    color:@color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.popup.less b/src/less/widget/multidate/multidate.popup.less
new file mode 100644
index 000000000..cb25ae6c3
--- /dev/null
+++ b/src/less/widget/multidate/multidate.popup.less
@@ -0,0 +1,28 @@
+@import "../../bibase";
+
+.bi-multidate-popup{
+
+  & .bi-multidate-popup-label {
+    color:@color-bi-text-highlight;
+    font-size:@font-size-14;
+    border-left:1px solid @color-bi-border-line;
+    border-right:1px solid @color-bi-border-line;
+    border-top:1px solid @color-bi-border-line;
+  }
+  & .bi-multidate-popup-tab {
+    border-bottom:1px solid @color-bi-border-line;
+  }
+  & .bi-multidate-popup-item{
+    &:active,&.active{
+      background-color: @color-bi-text-highlight;
+      color: @color-bi-background-default;
+      .border-corner-radius(@radius-2,@radius-2,0,0);
+    }
+  }
+
+  & .bi-multidate-popup-button{
+    color:@color-bi-text-highlight;
+    font-size:@font-size-14;
+    border-top:1px solid @color-bi-border-line;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.quarter.less b/src/less/widget/multidate/multidate.quarter.less
new file mode 100644
index 000000000..7cbb1e158
--- /dev/null
+++ b/src/less/widget/multidate/multidate.quarter.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multidate-quartercard{
+  & .bi-multidate-inner-label{
+    //font-size:@font-size-14;
+    color:@color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.segment.less b/src/less/widget/multidate/multidate.segment.less
new file mode 100644
index 000000000..ba5577ca2
--- /dev/null
+++ b/src/less/widget/multidate/multidate.segment.less
@@ -0,0 +1,10 @@
+@import "../../bibase";
+
+.bi-multidate-segment{
+  & .bi-multidate-normal-label{
+    color:@color-bi-text-black;
+  }
+  & .bi-multidate-editor{
+    font-size: @font-size-14;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.week.less b/src/less/widget/multidate/multidate.week.less
new file mode 100644
index 000000000..2f83c1877
--- /dev/null
+++ b/src/less/widget/multidate/multidate.week.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multidate-weekcard{
+  & .bi-multidate-inner-label{
+    //font-size:@font-size-14;
+    color:@color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multidate/multidate.year.less b/src/less/widget/multidate/multidate.year.less
new file mode 100644
index 000000000..f13afd566
--- /dev/null
+++ b/src/less/widget/multidate/multidate.year.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multidate-yearcard{
+  & .bi-multidate-inner-label{
+    //font-size:@font-size-14;
+    color:@color-bi-text-gray;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/check/multiselect.check.pane.less b/src/less/widget/multiselect/check/multiselect.check.pane.less
new file mode 100644
index 000000000..e17caac1f
--- /dev/null
+++ b/src/less/widget/multiselect/check/multiselect.check.pane.less
@@ -0,0 +1,12 @@
+@import "../../../bibase";
+
+
+.bi-multi-select-check-pane{
+  & .multi-select-continue-select{
+    background-color: @color-bi-background-gray;
+  }
+  & .multi-select-check-selected{
+    color: @color-bi-text-highlight;
+    text-decoration: underline;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/check/multiselect.display.less b/src/less/widget/multiselect/check/multiselect.display.less
new file mode 100644
index 000000000..5ba0fbecc
--- /dev/null
+++ b/src/less/widget/multiselect/check/multiselect.display.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-display-list{
+    background-color: @color-bi-background-gray;
+    & .display-list-item{
+      color: @color-bi-text-gray;
+    }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/multiselect.combo.less b/src/less/widget/multiselect/multiselect.combo.less
new file mode 100644
index 000000000..3ebb3fc47
--- /dev/null
+++ b/src/less/widget/multiselect/multiselect.combo.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multi-select-combo{
+  & .multi-select-trigger-icon-button{
+    border-left: 1px solid @color-bi-border-normal;
+    font-size: 16px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/multiselect.popup.view.less b/src/less/widget/multiselect/multiselect.popup.view.less
new file mode 100644
index 000000000..deba5ba42
--- /dev/null
+++ b/src/less/widget/multiselect/multiselect.popup.view.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+
+.bi-multi-select-popup-view{
+  & .multi-select-no-toolbar{
+    color:@font-color-disabled
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/multiselect.trigger.less b/src/less/widget/multiselect/multiselect.trigger.less
new file mode 100644
index 000000000..1d68ba7f5
--- /dev/null
+++ b/src/less/widget/multiselect/multiselect.trigger.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+.bi-multi-select-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-corner-radius(2px, 2px, 2px, 2px);
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/search/multiselect.search.pane.less b/src/less/widget/multiselect/search/multiselect.search.pane.less
new file mode 100644
index 000000000..73e42e967
--- /dev/null
+++ b/src/less/widget/multiselect/search/multiselect.search.pane.less
@@ -0,0 +1,9 @@
+@import "../../../bibase";
+
+
+.bi-multi-select-search-pane{
+  background:@color-bi-background-default;
+  .multi-select-toolbar{
+    color: @color-bi-text-warning;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multiselect/trigger/button.checkselected.less b/src/less/widget/multiselect/trigger/button.checkselected.less
new file mode 100644
index 000000000..20645ae5e
--- /dev/null
+++ b/src/less/widget/multiselect/trigger/button.checkselected.less
@@ -0,0 +1,9 @@
+@import "../../../bibase";
+
+.bi-multi-select-check-selected-button {
+  border: 1px solid @color-bi-text-highlight;
+  .border-corner-radius(8px, 8px, 8px, 8px);
+  color: @color-bi-text-highlight;
+  background-color: @color-bi-background-default;
+  z-index: 1;
+}
\ No newline at end of file
diff --git a/src/less/widget/multistringlist/multistringlist.less b/src/less/widget/multistringlist/multistringlist.less
new file mode 100644
index 000000000..0d10f755c
--- /dev/null
+++ b/src/less/widget/multistringlist/multistringlist.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+.bi-multi-string-list{
+  & .popup-multi-string-list{
+    border-left: 1px solid @color-bi-border-normal;
+    border-right: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/check/multi.tree.check.pane.less b/src/less/widget/multitree/check/multi.tree.check.pane.less
new file mode 100644
index 000000000..93ac62973
--- /dev/null
+++ b/src/less/widget/multitree/check/multi.tree.check.pane.less
@@ -0,0 +1,12 @@
+@import "../../../bibase";
+
+
+.bi-multi-tree-check-pane{
+  background-color: @color-bi-background-gray;
+  & .multi-tree-continue-select{
+    background-color: @color-bi-background-gray;
+  }
+  & .multi-tree-check-selected{
+    color: @color-bi-text-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/display.multi.tree.less b/src/less/widget/multitree/display.multi.tree.less
new file mode 100644
index 000000000..01dd64b22
--- /dev/null
+++ b/src/less/widget/multitree/display.multi.tree.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-multi-tree-display{
+  background-color: @color-bi-background-gray;
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/multi.tree.combo.less b/src/less/widget/multitree/multi.tree.combo.less
new file mode 100644
index 000000000..83de855f4
--- /dev/null
+++ b/src/less/widget/multitree/multi.tree.combo.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-multi-tree-combo{
+  & .multi-select-trigger-icon-button{
+    border-left: 1px solid @color-bi-border-normal;
+    font-size: 16px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/multi.tree.trigger.less b/src/less/widget/multitree/multi.tree.trigger.less
new file mode 100644
index 000000000..a132b0fc9
--- /dev/null
+++ b/src/less/widget/multitree/multi.tree.trigger.less
@@ -0,0 +1,18 @@
+@import "../../bibase";
+
+.bi-multi-tree-trigger{
+  border: 1px solid @color-bi-border-normal;
+  .border-corner-radius(2px, 2px, 2px, 2px);
+  & .trigger-check-selected{
+    border: 1px solid @color-bi-text-highlight;
+    .border-corner-radius(8px, 8px, 8px, 8px);
+    color: @color-bi-text-highlight;
+    background-color: @color-bi-background-default;
+    z-index: 1;
+  }
+
+  & .trigger-icon-button{
+    border-left: 1px solid @color-bi-border-normal;
+    font-size: 16px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/popup.multi.tree.less b/src/less/widget/multitree/popup.multi.tree.less
new file mode 100644
index 000000000..420943841
--- /dev/null
+++ b/src/less/widget/multitree/popup.multi.tree.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-multi-tree-popup{
+  & .popup-view-tree{
+    min-height: 170px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/search.multi.tree.less b/src/less/widget/multitree/search.multi.tree.less
new file mode 100644
index 000000000..04edbd5e9
--- /dev/null
+++ b/src/less/widget/multitree/search.multi.tree.less
@@ -0,0 +1,6 @@
+@import "../../bibase";
+
+
+.bi-multi-tree-search-pane{
+  background: @color-bi-background-default;
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/trigger.multi.tree.less b/src/less/widget/multitree/trigger.multi.tree.less
new file mode 100644
index 000000000..a132b0fc9
--- /dev/null
+++ b/src/less/widget/multitree/trigger.multi.tree.less
@@ -0,0 +1,18 @@
+@import "../../bibase";
+
+.bi-multi-tree-trigger{
+  border: 1px solid @color-bi-border-normal;
+  .border-corner-radius(2px, 2px, 2px, 2px);
+  & .trigger-check-selected{
+    border: 1px solid @color-bi-text-highlight;
+    .border-corner-radius(8px, 8px, 8px, 8px);
+    color: @color-bi-text-highlight;
+    background-color: @color-bi-background-default;
+    z-index: 1;
+  }
+
+  & .trigger-icon-button{
+    border-left: 1px solid @color-bi-border-normal;
+    font-size: 16px;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitree/trigger/multi.tree.button.checkselected.less b/src/less/widget/multitree/trigger/multi.tree.button.checkselected.less
new file mode 100644
index 000000000..2049bc2c9
--- /dev/null
+++ b/src/less/widget/multitree/trigger/multi.tree.button.checkselected.less
@@ -0,0 +1,11 @@
+@import "../../../bibase";
+
+.bi-multi-tree-check-selected-button {
+  & .trigger-check-selected{
+    border: 1px solid @color-bi-text-highlight;
+    .border-corner-radius(8px, 8px, 8px, 8px);
+    color: @color-bi-text-highlight;
+    background-color: @color-bi-background-default;
+    z-index: 1;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/multitreelist/multitreelist.popup.less b/src/less/widget/multitreelist/multitreelist.popup.less
new file mode 100644
index 000000000..741c1fc2b
--- /dev/null
+++ b/src/less/widget/multitreelist/multitreelist.popup.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-tree-list-popup {
+  border-left: 1px solid @color-bi-border-normal;
+  border-right: 1px solid @color-bi-border-normal;
+  border-bottom: 1px solid @color-bi-border-normal;
+}
\ No newline at end of file
diff --git a/src/less/widget/numericalinterval/numericalinterval.less b/src/less/widget/numericalinterval/numericalinterval.less
new file mode 100644
index 000000000..90bf571a4
--- /dev/null
+++ b/src/less/widget/numericalinterval/numericalinterval.less
@@ -0,0 +1,39 @@
+@import "../../bibase";
+
+.bi-numerical-interval {
+  & .numerical-interval-small-editor {
+    border-top: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+    border-left: 1px solid @color-bi-border-normal;
+    .border-corner-left-radius(2px, 2px);
+  }
+  & .numerical-interval-big-editor {
+    border-top: 1px solid @color-bi-border-normal;
+    border-bottom: 1px solid @color-bi-border-normal;
+    border-right: 1px solid @color-bi-border-normal;
+    .border-corner-right-radius(2px, 2px);
+  }
+  & .numerical-interval-big-combo {
+    border: 1px solid @color-bi-border-normal;
+    .border-corner-left-radius(2px, 2px);
+    & .bi-icon-combo-trigger {
+      & .icon-combo-trigger-icon {
+        font-size: @font-size-14;
+      }
+    }
+  }
+
+  & .numerical-interval-small-combo {
+    border: 1px solid @color-bi-border-normal;
+    .border-corner-right-radius(2px, 2px);
+    & .bi-icon-combo-trigger {
+      & .icon-combo-trigger-icon {
+        font-size: @font-size-14;
+      }
+    }
+  }
+
+  &.number-error .bi-input {
+    color: @color-bi-text-warning
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/numericalinterval/popup.numericalinterval.less b/src/less/widget/numericalinterval/popup.numericalinterval.less
new file mode 100644
index 000000000..9fbdae27f
--- /dev/null
+++ b/src/less/widget/numericalinterval/popup.numericalinterval.less
@@ -0,0 +1,13 @@
+@import "../../bibase";
+
+.bi-numerical-interval-popup{
+  & .numerical-interval-popup-item{
+    &.hover, &:hover{
+      background-color: @color-bi-background-gray;
+    }
+    &.active, &:active{
+      background-color: @color-bi-background-gray;
+      color: @color-bi-text-highlight;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/pagetable/pagetable.cell.less b/src/less/widget/pagetable/pagetable.cell.less
new file mode 100644
index 000000000..1628cb806
--- /dev/null
+++ b/src/less/widget/pagetable/pagetable.cell.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-page-table-cell {
+  .user-select(initial);
+}
\ No newline at end of file
diff --git a/src/less/widget/pagetable/pagetable.less b/src/less/widget/pagetable/pagetable.less
new file mode 100644
index 000000000..79a629fd4
--- /dev/null
+++ b/src/less/widget/pagetable/pagetable.less
@@ -0,0 +1,4 @@
+@import "../../bibase";
+
+.bi-page-table {
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/datecombo/combo.param.date.less b/src/less/widget/paramsettingcombo/datecombo/combo.param.date.less
new file mode 100644
index 000000000..c827a4929
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/datecombo/combo.param.date.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-date-param-combo{
+  & .param-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px)
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.less b/src/less/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.less
new file mode 100644
index 000000000..71dae21ab
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-date-interval-param-combo{
+  & .param-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px)
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/param0.date.item.less b/src/less/widget/paramsettingcombo/param0.date.item.less
new file mode 100644
index 000000000..bb1010878
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/param0.date.item.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-param0-date-item{
+  & .param-label{
+    color: @color-bi-text-gray
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/param1.date.item.less b/src/less/widget/paramsettingcombo/param1.date.item.less
new file mode 100644
index 000000000..4b8d8a957
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/param1.date.item.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-param1-date-item{
+  & .param-label{
+    color: @color-bi-text-gray
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/param2.date.item.less b/src/less/widget/paramsettingcombo/param2.date.item.less
new file mode 100644
index 000000000..4f3fe28a3
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/param2.date.item.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-param2-date-item{
+  & .param-label{
+    color: @color-bi-text-gray
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/yearcombo/combo.param.year.less b/src/less/widget/paramsettingcombo/yearcombo/combo.param.year.less
new file mode 100644
index 000000000..1edcb8a74
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/yearcombo/combo.param.year.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-year-param-combo{
+  & .param-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px)
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.less b/src/less/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.less
new file mode 100644
index 000000000..e899f1162
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-year-month-param-combo{
+  & .param-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px)
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.less b/src/less/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.less
new file mode 100644
index 000000000..150f84b61
--- /dev/null
+++ b/src/less/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.less
@@ -0,0 +1,8 @@
+@import "../../../bibase";
+
+.bi-year-season-param-combo{
+  & .param-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px)
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/pathchooser/pathchooser.less b/src/less/widget/pathchooser/pathchooser.less
new file mode 100644
index 000000000..2a0bee5bc
--- /dev/null
+++ b/src/less/widget/pathchooser/pathchooser.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-path-chooser {
+  & .path-chooser-radio {
+    z-index: 1;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/pathchooser/pathregion.less b/src/less/widget/pathchooser/pathregion.less
new file mode 100644
index 000000000..c2704012b
--- /dev/null
+++ b/src/less/widget/pathchooser/pathregion.less
@@ -0,0 +1,14 @@
+@import "../../bibase";
+
+.bi-path-region {
+  background: @color-bi-background-light;
+  & .path-region-label {
+    z-index: 1;
+    background: @color-bi-background-default;
+    border: 1px solid @color-bi-border-default;
+    &.active{
+      background: @color-bi-background-highlight;
+      color: @color-bi-text;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/previewtable/previewtable.cell.less b/src/less/widget/previewtable/previewtable.cell.less
new file mode 100644
index 000000000..ecfaa200b
--- /dev/null
+++ b/src/less/widget/previewtable/previewtable.cell.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+
+.bi-preview-table-cell {
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
\ No newline at end of file
diff --git a/src/less/widget/previewtable/previewtable.header.cell.less b/src/less/widget/previewtable/previewtable.header.cell.less
new file mode 100644
index 000000000..5711309df
--- /dev/null
+++ b/src/less/widget/previewtable/previewtable.header.cell.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-preview-table-header-cell {
+  font-weight: bold;
+  min-height: 25px;
+  min-width: 80px;
+  max-width: 220px;
+}
\ No newline at end of file
diff --git a/src/less/widget/previewtable/previewtable.less b/src/less/widget/previewtable/previewtable.less
new file mode 100644
index 000000000..b5926366a
--- /dev/null
+++ b/src/less/widget/previewtable/previewtable.less
@@ -0,0 +1,9 @@
+@import "../../bibase";
+
+.bi-preview-table {
+  & > div > table, & > div > div > div > table {
+    & > thead > tr.odd {
+      background-color: @color-bi-background-light;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/quarter/combo.quarter.less b/src/less/widget/quarter/combo.quarter.less
new file mode 100644
index 000000000..20a071e8e
--- /dev/null
+++ b/src/less/widget/quarter/combo.quarter.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-quarter-combo{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/quarter/popup.quarter.less b/src/less/widget/quarter/popup.quarter.less
new file mode 100644
index 000000000..1d69d158d
--- /dev/null
+++ b/src/less/widget/quarter/popup.quarter.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-quarter-popup{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/quarter/trigger.quarter.less b/src/less/widget/quarter/trigger.quarter.less
new file mode 100644
index 000000000..37dceed98
--- /dev/null
+++ b/src/less/widget/quarter/trigger.quarter.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+.bi-quarter-trigger{
+  border: 1px solid @color-bi-border-normal;
+  .border-radius(2px);
+}
\ No newline at end of file
diff --git a/src/less/widget/relationview/relationview.item.less b/src/less/widget/relationview/relationview.item.less
new file mode 100644
index 000000000..687357034
--- /dev/null
+++ b/src/less/widget/relationview/relationview.item.less
@@ -0,0 +1,8 @@
+@import "../../bibase";
+
+.bi-relation-view-item{
+  &.active{
+    color: @color-bi-text;
+    background-color: @color-bi-background-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/relationview/relationview.region.less b/src/less/widget/relationview/relationview.region.less
new file mode 100644
index 000000000..06a8d89b9
--- /dev/null
+++ b/src/less/widget/relationview/relationview.region.less
@@ -0,0 +1,16 @@
+@import "../../bibase";
+
+.bi-relation-view-region{
+  & .relation-view-region-container{
+    background: @color-bi-background-default;
+    border: 1px solid @color-bi-border-normal;
+    &.other-package{
+      border: 1px dashed @color-bi-border-normal;
+    }
+    z-index: 1;
+    .border-radius(2px);
+    & .relation-view-region-title{
+      border-bottom: 1px solid @color-bi-border-normal;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/searchpane/result.search.selectdata.less b/src/less/widget/selectdata/searchpane/result.search.selectdata.less
new file mode 100644
index 000000000..3c1a829ad
--- /dev/null
+++ b/src/less/widget/selectdata/searchpane/result.search.selectdata.less
@@ -0,0 +1,11 @@
+@import "../../../bibase";
+
+
+.bi-select-data-search-result-pane{
+  & .search-result-toolbar{
+
+  }
+  & .search-result-line{
+    border-top: 1px solid @color-bi-border-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/searchpane/searcher.selectdata.less b/src/less/widget/selectdata/searchpane/searcher.selectdata.less
new file mode 100644
index 000000000..424732a76
--- /dev/null
+++ b/src/less/widget/selectdata/searchpane/searcher.selectdata.less
@@ -0,0 +1,6 @@
+@import "../../../bibase";
+
+
+.bi-select-data-searcher{
+  font-size: @font-size-13;
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/searchpane/segment.search.selectdata.less b/src/less/widget/selectdata/searchpane/segment.search.selectdata.less
new file mode 100644
index 000000000..d08c6ed44
--- /dev/null
+++ b/src/less/widget/selectdata/searchpane/segment.search.selectdata.less
@@ -0,0 +1,14 @@
+@import "../../../bibase";
+
+
+.bi-select-data-search-segment{
+
+  & .search-segment-field-table{
+    & > .first-element{
+      .border-corner-radius(3px,0px,0px,3px)
+    }
+    & > .last-element{
+      .border-corner-radius(0px,3,3px,0px)
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/searchpane/tab.search.selectdata.less b/src/less/widget/selectdata/searchpane/tab.search.selectdata.less
new file mode 100644
index 000000000..3d0e4ed65
--- /dev/null
+++ b/src/less/widget/selectdata/searchpane/tab.search.selectdata.less
@@ -0,0 +1,6 @@
+@import "../../../bibase";
+
+
+.bi-select-data-search-tab{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/expander.selectdata.less b/src/less/widget/selectdata/tree/expander.selectdata.less
new file mode 100644
index 000000000..0573376d3
--- /dev/null
+++ b/src/less/widget/selectdata/tree/expander.selectdata.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-select-data-expander{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/node/node.level0.less b/src/less/widget/selectdata/tree/node/node.level0.less
new file mode 100644
index 000000000..7a30ff1a8
--- /dev/null
+++ b/src/less/widget/selectdata/tree/node/node.level0.less
@@ -0,0 +1,7 @@
+@import "../../../../bibase";
+
+.bi-select-data-level0-node{
+  & .select-data-selected-count-label{
+    color: @color-bi-text-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/node/node.level1.less b/src/less/widget/selectdata/tree/node/node.level1.less
new file mode 100644
index 000000000..3f6b9095b
--- /dev/null
+++ b/src/less/widget/selectdata/tree/node/node.level1.less
@@ -0,0 +1,7 @@
+@import "../../../../bibase";
+
+.bi-select-data-level1-node{
+  & .select-data-selected-count-label{
+    color: @color-bi-text-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/tree.selectdata.less b/src/less/widget/selectdata/tree/tree.selectdata.less
new file mode 100644
index 000000000..981479184
--- /dev/null
+++ b/src/less/widget/selectdata/tree/tree.selectdata.less
@@ -0,0 +1,5 @@
+@import "../../../bibase";
+
+.bi-select-data-tree{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/treeitem/item.level0.less b/src/less/widget/selectdata/tree/treeitem/item.level0.less
new file mode 100644
index 000000000..c07a7eb27
--- /dev/null
+++ b/src/less/widget/selectdata/tree/treeitem/item.level0.less
@@ -0,0 +1,24 @@
+@import "../../../../bibase";
+
+.bi-select-data-level0-item {
+  & .select-data-level0-item-button {
+    .border-radius(3px);
+    .list-item-select();
+  }
+
+  & .select-data-top-line, & .select-data-bottom-line {
+    background-color: @color-bi-background-highlight;
+  }
+
+  &.select-data-item-top {
+    & .select-data-level0-item-button {
+      .border-corner-top-radius(0, 0);
+    }
+  }
+
+  &.select-data-item-bottom {
+    & .select-data-level0-item-button {
+      .border-corner-bottom-radius(0, 0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selectdata/tree/treeitem/item.level1.less b/src/less/widget/selectdata/tree/treeitem/item.level1.less
new file mode 100644
index 000000000..f051c9a2c
--- /dev/null
+++ b/src/less/widget/selectdata/tree/treeitem/item.level1.less
@@ -0,0 +1,24 @@
+@import "../../../../bibase";
+
+.bi-select-data-level1-item {
+  & .select-data-level1-item-button {
+    .border-radius(3px);
+    .list-item-select();
+  }
+
+  & .select-data-top-line, & .select-data-bottom-line {
+    background-color: @color-bi-background-highlight;
+  }
+
+  &.select-data-item-top {
+    & .select-data-level1-item-button {
+      .border-corner-top-radius(0, 0);
+    }
+  }
+
+  &.select-data-item-bottom {
+    & .select-data-level1-item-button {
+      .border-corner-bottom-radius(0, 0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selecttable/single/button.databasetable.less b/src/less/widget/selecttable/single/button.databasetable.less
new file mode 100644
index 000000000..2ef18931c
--- /dev/null
+++ b/src/less/widget/selecttable/single/button.databasetable.less
@@ -0,0 +1,78 @@
+@import "../../../bibase";
+
+.bi-database-table {
+  .border-radius(2px);
+  border: 1px solid @color-bi-border-normal;
+  background: @color-bi-background-default;
+  &.active {
+    background: @color-bi-background-highlight;
+    color: @color-bi-text;
+  }
+  & .table-name-text {
+    max-width: 300px;
+  }
+  & .table-font {
+    font-size: @font-size-16;
+  }
+  & .table-conn-label1 {
+    background-color: @color-bi-data-link-button-color1;
+  }
+  & .table-conn-label2 {
+    background-color: @color-bi-data-link-button-color2;
+  }
+  & .table-conn-label3 {
+    background-color: @color-bi-data-link-button-color3;
+  }
+  & .table-conn-label4 {
+    background-color: @color-bi-data-link-button-color4;
+  }
+  & .table-conn-label5 {
+    background-color: @color-bi-data-link-button-color5;
+  }
+  & .table-conn-label6 {
+    background-color: @color-bi-data-link-button-color6;
+  }
+  & .table-conn-label7 {
+    background-color: @color-bi-data-link-button-color7;
+  }
+  & .table-conn-label8 {
+    background-color: @color-bi-data-link-button-color8;
+  }
+  & .table-conn-label9 {
+    background-color: @color-bi-data-link-button-color9;
+  }
+  & .table-conn-label10 {
+    background-color: @color-bi-data-link-button-color10;
+  }
+
+  &.table-selected1.active {
+    background-color: @color-bi-data-link-button-color1;
+  }
+  &.table-selected2.active {
+    background-color: @color-bi-data-link-button-color2;
+  }
+  &.table-selected3.active {
+    background-color: @color-bi-data-link-button-color3;
+  }
+  &.table-selected4.active {
+    background-color: @color-bi-data-link-button-color4;
+  }
+  &.table-selected5.active {
+    background-color: @color-bi-data-link-button-color5;
+  }
+  &.table-selected6.active {
+    background-color: @color-bi-data-link-button-color6;
+  }
+  &.table-selected7.active {
+    background-color: @color-bi-data-link-button-color7;
+  }
+  &.table-selected8.active {
+    background-color: @color-bi-data-link-button-color8;
+  }
+  &.table-selected9.active {
+    background-color: @color-bi-data-link-button-color9;
+  }
+  &.table-selected10.active {
+    background-color: @color-bi-data-link-button-color10;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/selecttree/combo.select.tree.less b/src/less/widget/selecttree/combo.select.tree.less
new file mode 100644
index 000000000..799b93497
--- /dev/null
+++ b/src/less/widget/selecttree/combo.select.tree.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+.bi-selecttree-combo{
+  & .selecttree-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px);
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/sequencetable/dynamicnumber.sequencetable.less b/src/less/widget/sequencetable/dynamicnumber.sequencetable.less
new file mode 100644
index 000000000..e324a582e
--- /dev/null
+++ b/src/less/widget/sequencetable/dynamicnumber.sequencetable.less
@@ -0,0 +1,15 @@
+@import "../../bibase";
+
+.bi-sequence-table-dynamic-number {
+  & .sequence-table-title-cell {
+    .overflow-hidden();
+    .box-sizing(border-box);
+    border: 1px solid @color-bi-border-line;
+  }
+  & .sequence-table-number-cell {
+    .box-sizing(border-box);
+    border-left: 1px solid @color-bi-border-line;
+    border-right: 1px solid @color-bi-border-line;
+    border-bottom: 1px solid @color-bi-border-line;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/sequencetable/listnumber.sequencetable.less b/src/less/widget/sequencetable/listnumber.sequencetable.less
new file mode 100644
index 000000000..bd9ad53a1
--- /dev/null
+++ b/src/less/widget/sequencetable/listnumber.sequencetable.less
@@ -0,0 +1,15 @@
+@import "../../bibase";
+
+.bi-sequence-table-list-number {
+  & .sequence-table-title-cell {
+    .overflow-hidden();
+    .box-sizing(border-box);
+    border: 1px solid @color-bi-border-line;
+  }
+  & .sequence-table-number-cell {
+    .box-sizing(border-box);
+    border-left: 1px solid @color-bi-border-line;
+    border-right: 1px solid @color-bi-border-line;
+    border-bottom: 1px solid @color-bi-border-line;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/sequencetable/sequencetable.less b/src/less/widget/sequencetable/sequencetable.less
new file mode 100644
index 000000000..a2a682137
--- /dev/null
+++ b/src/less/widget/sequencetable/sequencetable.less
@@ -0,0 +1,4 @@
+@import "../../bibase";
+
+.bi-sequence-table{
+}
\ No newline at end of file
diff --git a/src/less/widget/sequencetable/treenumber.sequencetable.less b/src/less/widget/sequencetable/treenumber.sequencetable.less
new file mode 100644
index 000000000..6400695b1
--- /dev/null
+++ b/src/less/widget/sequencetable/treenumber.sequencetable.less
@@ -0,0 +1,15 @@
+@import "../../bibase";
+
+.bi-sequence-table-tree-number {
+  & .sequence-table-title-cell {
+    .overflow-hidden();
+    .box-sizing(border-box);
+    border: 1px solid @color-bi-border-line;
+  }
+  & .sequence-table-number-cell {
+    .box-sizing(border-box);
+    border-left: 1px solid @color-bi-border-line;
+    border-right: 1px solid @color-bi-border-line;
+    border-bottom: 1px solid @color-bi-border-line;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/singleslider/singleslider.less b/src/less/widget/singleslider/singleslider.less
new file mode 100644
index 000000000..12cbd50b6
--- /dev/null
+++ b/src/less/widget/singleslider/singleslider.less
@@ -0,0 +1,13 @@
+@import "../../bibase";
+.bi-single-slider{
+  & .slider-editor-button{
+    & .sign-editor-text{
+      &:hover {
+        border:1px solid @border-color-normal;
+      }
+    }
+    & .bi-editor{
+      border:1px solid @border-color-normal;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/singleslider/slider/widget.slider.less b/src/less/widget/singleslider/slider/widget.slider.less
new file mode 100644
index 000000000..297bd13f2
--- /dev/null
+++ b/src/less/widget/singleslider/slider/widget.slider.less
@@ -0,0 +1,4 @@
+@import "../../../bibase";
+.bi-single-slider-slider{
+  cursor: url('@{leftRightCursor}'), auto;
+}
\ No newline at end of file
diff --git a/src/less/widget/singleslider/track/widget.track.less b/src/less/widget/singleslider/track/widget.track.less
new file mode 100644
index 000000000..669f020e6
--- /dev/null
+++ b/src/less/widget/singleslider/track/widget.track.less
@@ -0,0 +1,24 @@
+@import "../../../bibase";
+.bi-slider-track{
+  .background-track{
+    background-color: @background-color-active;
+    .border-radius(12px);
+  }
+  .gray-track{
+    background: @water-mark-color;
+    .border-radius(4px);
+  }
+  .blue-track{
+    background: @background-color-highlight;
+    .border-radius(4px);
+  }
+  //.track-blue{
+  //  background: @background-color-highlight;
+  //  .border-radius(@radius-5);
+  //}
+  //.track{
+  //  background-color: @water-mark-color;
+  //  border: 7px solid @background-color-active;
+  //  .border-radius(@radius-12);
+  //}
+}
\ No newline at end of file
diff --git a/src/less/widget/singletree/combo.single.tree.less b/src/less/widget/singletree/combo.single.tree.less
new file mode 100644
index 000000000..6089b33da
--- /dev/null
+++ b/src/less/widget/singletree/combo.single.tree.less
@@ -0,0 +1,12 @@
+@import "../../bibase";
+.bi-singletree-combo{
+  & .singletree-trigger{
+    border: 1px solid @color-bi-border-normal;
+    .border-radius(2px);
+  }
+  & .bi-singletree-popup{
+    & .singletree-toolbar {
+      color: @font-color-disabled
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/sortabletable/sortabletable.less b/src/less/widget/sortabletable/sortabletable.less
new file mode 100644
index 000000000..2d88930ba
--- /dev/null
+++ b/src/less/widget/sortabletable/sortabletable.less
@@ -0,0 +1,15 @@
+@import "../../bibase";
+
+.bi-sortable-table{
+  & .sortable_table_drag_clone {
+    background: @background-color-light-blue;
+    top: 0px;
+    opacity: (0.5);
+  }
+  & .drag-header{
+    cursor: move;
+  }
+  & .insert-help-line {
+    border-right: 3px dashed @background-color-highlight;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/textarea/textarea.less b/src/less/widget/textarea/textarea.less
new file mode 100644
index 000000000..6a17a6d8a
--- /dev/null
+++ b/src/less/widget/textarea/textarea.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+.bi-text-area{
+  & .text-area-editor-text-button-label{
+    font-size: @font-size-16;
+    color:  @font-color-tips;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.less b/src/less/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.less
new file mode 100644
index 000000000..85da62e50
--- /dev/null
+++ b/src/less/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.less
@@ -0,0 +1,11 @@
+@import "../../../bibase";
+.bi-text-toolbar-align-chooser{
+  & .align-chooser-button{
+    &:hover{
+      background-color: @background-color-disabled;
+    }
+    &.active{
+      background-color: @background-color-disabled;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/texttoolbar/texttoolbar.less b/src/less/widget/texttoolbar/texttoolbar.less
new file mode 100644
index 000000000..ffd4789f6
--- /dev/null
+++ b/src/less/widget/texttoolbar/texttoolbar.less
@@ -0,0 +1,14 @@
+@import "../../bibase";
+.bi-text-toolbar{
+  background: @background-color-light;
+  & .text-toolbar-button {
+    font-size: @font-size-16;
+  }
+  & .text-toolbar-size-chooser-trigger{
+    background: @background-color-default;
+    font-size: @font-size-12;
+    & a{
+      font-size: @font-size-12;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/timeinterval/timeinterval.less b/src/less/widget/timeinterval/timeinterval.less
new file mode 100644
index 000000000..9d3a2e195
--- /dev/null
+++ b/src/less/widget/timeinterval/timeinterval.less
@@ -0,0 +1,10 @@
+@import "../../bibase";
+
+.bi-param-time-interval{
+  &.time-error .bi-input{
+    color:@color-bi-text-warning
+  }
+  &.time-error .sign-editor-text{
+    color:@color-bi-text-warning
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/timesetting/timesetting.day.less b/src/less/widget/timesetting/timesetting.day.less
new file mode 100644
index 000000000..c411085f3
--- /dev/null
+++ b/src/less/widget/timesetting/timesetting.day.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+.bi-time-setting-day{
+    .operator-button{
+      .border-radius(2px);
+      border: 1px solid @color-bi-border-normal;
+    }
+}
\ No newline at end of file
diff --git a/src/less/widget/timesetting/timesetting.hour.less b/src/less/widget/timesetting/timesetting.hour.less
new file mode 100644
index 000000000..580e8ac26
--- /dev/null
+++ b/src/less/widget/timesetting/timesetting.hour.less
@@ -0,0 +1,7 @@
+@import "../../bibase";
+.bi-time-setting-hour{
+  .operator-button{
+    .border-radius(2px);
+    border: 1px solid @color-bi-border-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/treelabel/treelabel.less b/src/less/widget/treelabel/treelabel.less
new file mode 100644
index 000000000..a9092777b
--- /dev/null
+++ b/src/less/widget/treelabel/treelabel.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-tree-label {
+  font-size: @font-size-14;
+}
\ No newline at end of file
diff --git a/src/less/widget/treelabel/treelabel.view.less b/src/less/widget/treelabel/treelabel.view.less
new file mode 100644
index 000000000..37361cdd8
--- /dev/null
+++ b/src/less/widget/treelabel/treelabel.view.less
@@ -0,0 +1,4 @@
+@import "../../bibase";
+.bi-tree-label-view {
+  // min-width: 330px;
+}
\ No newline at end of file
diff --git a/src/less/widget/web/web.less b/src/less/widget/web/web.less
new file mode 100644
index 000000000..ec1b27c23
--- /dev/null
+++ b/src/less/widget/web/web.less
@@ -0,0 +1,17 @@
+@import "../../bibase";
+.bi-web-page{
+  & .web-page-button {
+    z-index: 1;
+    font-size: @font-size-14;
+    background-color: @color-bi-background-default;
+  }
+  & .web-page-text-button-label{
+    font-size: @font-size-16;
+    color:  @font-color-tips
+  }
+
+  & .web-page-delete-label{
+    font-size: @font-size-14;
+    color: @font-color-normal;
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/year/combo.year.less b/src/less/widget/year/combo.year.less
new file mode 100644
index 000000000..1b441ba64
--- /dev/null
+++ b/src/less/widget/year/combo.year.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+
+.bi-year-combo{
+
+}
\ No newline at end of file
diff --git a/src/less/widget/year/popup.year.less b/src/less/widget/year/popup.year.less
new file mode 100644
index 000000000..087bd93ce
--- /dev/null
+++ b/src/less/widget/year/popup.year.less
@@ -0,0 +1,15 @@
+@import "../../bibase";
+
+.bi-year-popup{
+  & .year-popup-navigation{
+    border-top: 1px solid @color-bi-split-light;
+    line-height: 30px;
+    color: @color-bi-text-highlight;
+    & > .center-element {
+      border-left: 1px solid @color-bi-split-light;
+    }
+    & > .first-element{
+      border-left: none;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/less/widget/year/trigger.year.less b/src/less/widget/year/trigger.year.less
new file mode 100644
index 000000000..2e711144d
--- /dev/null
+++ b/src/less/widget/year/trigger.year.less
@@ -0,0 +1,5 @@
+@import "../../bibase";
+.bi-year-trigger{
+  border: 1px solid @color-bi-border-normal;
+  .border-radius(2px);
+}
\ No newline at end of file
diff --git a/src/third/codemirror/codemirror.js b/src/third/codemirror/codemirror.js
index 870197680..94ae8faad 100644
--- a/src/third/codemirror/codemirror.js
+++ b/src/third/codemirror/codemirror.js
@@ -8216,7 +8216,7 @@
   // Extending unicode characters. A series of a non-extending char +
   // any number of extending chars is treated as a single unit as far
   // as editing and measuring is concerned. This is not fully correct,
-  // since some scripts/fonts/browsers also treat other configurations
+  // since some scripts/font/browsers also treat other configurations
   // of code points as a group.
   var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
   function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
diff --git a/src/third/raphael.js b/src/third/raphael.js
index a05236321..2bbc32437 100644
--- a/src/third/raphael.js
+++ b/src/third/raphael.js
@@ -5469,7 +5469,7 @@
      * Raphael.registerFont
      [ method ]
      **
-     * Adds given font to the registered set of fonts for Raphaël. Should be used as an internal call from within Cufón’s font file.
+     * Adds given font to the registered set of font for Raphaël. Should be used as an internal call from within Cufón’s font file.
      * Returns original parameter, so it could be used with chaining.
      # <a href="http://wiki.github.com/sorccu/cufon/about">More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.</a>
      **
@@ -5523,7 +5523,7 @@
      * Paper.getFont
      [ method ]
      **
-     * Finds font object in the registered fonts by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
+     * Finds font object in the registered font by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”.
      **
      > Parameters
      **
diff --git a/src/widget/adaptivearrangement/adaptivearrangement.js b/src/widget/adaptivearrangement/adaptivearrangement.js
new file mode 100644
index 000000000..ec72886ac
--- /dev/null
+++ b/src/widget/adaptivearrangement/adaptivearrangement.js
@@ -0,0 +1,514 @@
+/**
+ * 自适应布局
+ *
+ * 1、resize
+ * 2、吸附
+ * 3、当前组件在最上方
+ * 4、可以撤销
+ * 5、上下之间插入组件
+ *
+ * Created by GUY on 2016/2/23.
+ * @class BI.AdaptiveArrangement
+ * @extends BI.Widget
+ */
+BI.AdaptiveArrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.AdaptiveArrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-adaptive-arrangement",
+            resizable: true,
+            isNeedReLayout: true,
+            isNeedResizeContainer: true,
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.AdaptiveArrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.arrangement",
+            element: this,
+            isNeedReLayout: o.isNeedReLayout,
+            layoutType: o.layoutType,
+            items: o.items
+        });
+        if (o.isNeedResizeContainer) {
+
+            var isResizing = false;
+            var height;
+            var interval;
+            var resize = function (e, ui) {
+                if (isResizing) {
+                    return;
+                }
+                isResizing = true;
+                height = ui.size.height;
+                interval = setInterval(function () {
+                    height += 40;
+                    self.arrangement.setContainerSize({
+                        width: ui.size.width,
+                        height: height
+                    });
+                    self.arrangement.scrollTo(height);
+                }, 500);
+            };
+            this.arrangement.container.element.resizable({
+                handles: "s",
+                minWidth: 100,
+                minHeight: 20,
+                helper: "bi-resizer",
+                autoHide: true,
+                resize: function (e, ui) {
+                    if (ui.size.height >= self.arrangement.container.element.height()) {
+                        resize(e, ui);
+                    } else {
+                        interval && clearInterval(interval);
+                    }
+                },
+                stop: function (e, ui) {
+                    var size = ui.size;
+                    if (isResizing) {
+                        size.height = height;
+                    }
+                    self.arrangement.setContainerSize(ui.size);
+                    isResizing = false;
+                    interval && clearInterval(interval);
+                    self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+                }
+            });
+            this._setLayoutType(o.layoutType);
+        }
+        this.zIndex = 0;
+        BI.each(o.items, function (i, item) {
+            self._initResizable(item.el);
+        });
+
+        this.element.click(function (e) {
+            BI.each(self.getAllRegions(), function (i, region) {
+                if (!region.el.element.__isMouseInBounds__(e)) {
+                    region.el.element.removeClass("selected");
+                }
+            });
+        });
+        BI.ResizeDetector.addResizeListener(this, function () {
+            self.arrangement.resize();
+            self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+        });
+    },
+
+    _isEqual: function () {
+        return this.arrangement._isEqual.apply(this.arrangement, arguments);
+    },
+
+    _initResizable: function (item) {
+        var self = this, o = this.options;
+        item.element.css("zIndex", ++this.zIndex);
+        item.element.mousedown(function () {
+            if (!item.element.hasClass("selected")) {
+                item.element.css("zIndex", ++self.zIndex);
+                BI.each(self.getAllRegions(), function (i, region) {
+                    region.el.element.removeClass("selected");
+                });
+                item.element.addClass("selected");
+            }
+        });
+        o.resizable && item.element.resizable({
+            handles: "e, s, se",
+            minWidth: 20,
+            minHeight: 20,
+            autoHide: true,
+            helper: "bi-resizer",
+            start: function () {
+                item.element.css("zIndex", ++self.zIndex);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE);
+            },
+            resize: function (e, ui) {
+                // self._resize(item.attr("id"), ui.size);
+                self._resize(item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, item.attr("id"), ui.size);
+            },
+            stop: function (e, ui) {
+                self._stopResize(item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, item.attr("id"), ui.size);
+                self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE);
+            }
+        });
+    },
+
+    _resize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.setRegionSize(name, size);
+                break;
+        }
+    },
+
+    _stopResize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                this.setRegionSize(name, {
+                    width: size.width,
+                    height: size.height
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                this.setRegionSize(name, size);
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.setRegionSize(name, size);
+                break;
+        }
+    },
+
+    //检查宽高是否规范
+    _checkRegionSize: function (name, size) {
+        var self = this;
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var newSize = {};
+                var leftid, rightid, topid, bottomid;
+                var region = this.getRegionByName(name);
+                var rs = this.arrangement._getInDirectRelativeRegions(name, ["right"]).right;
+                var bs = this.arrangement._getInDirectRelativeRegions(name, ["bottom"]).bottom;
+                if (rs.left.length > 0) {
+                    topid = BI.first(rs.left).id;
+                    bottomid = BI.last(rs.left).id;
+                }
+                if (bs.top.length > 0) {
+                    leftid = BI.first(bs.top).id;
+                    rightid = BI.last(bs.top).id;
+                }
+                if (this.arrangement._isEqual(region.width, size.width)) {
+                    topid = name;
+                    bottomid = name;
+                }
+                if (this.arrangement._isEqual(region.height, size.height)) {
+                    leftid = name;
+                    rightid = name;
+                }
+                var tops = topid ? this.getDirectRelativeRegions(topid, ["top"]).top : [];
+                var bottoms = bottomid ? this.getDirectRelativeRegions(bottomid, ["bottom"]).bottom : [];
+                var lefts = leftid ? this.getDirectRelativeRegions(leftid, ["left"]).left : [];
+                var rights = rightid ? this.getDirectRelativeRegions(rightid, ["right"]).right : [];
+                if (region.width !== size.width) {
+                    if (rights.length === 0) {//最右边的组件不能调整宽度
+                        newSize.width = region.width;
+                    } else {
+                        var finded = BI.find(tops.concat(bottoms), function (i, r) {
+                            r = self.getRegionByName(r.id);
+                            return Math.abs(size.width + region.left - (r.left + r.width)) <= 3;
+                        });
+                        if (finded) {
+                            finded = this.getRegionByName(finded.id);
+                            newSize.width = finded.left + finded.width - region.left;
+                        } else {
+                            newSize.width = size.width;
+                        }
+                    }
+                } else {
+                    newSize.width = size.width;
+                }
+                if (region.height !== size.height) {
+                    if (bottoms.length === 0) {
+                        newSize.height = region.height;
+                    } else {
+                        var finded = BI.find(lefts.concat(rights), function (i, r) {
+                            r = self.getRegionByName(r.id);
+                            return Math.abs(size.height + region.top - (r.top + r.height)) <= 3;
+                        });
+                        if (finded) {
+                            finded = this.getRegionByName(finded.id);
+                            newSize.height = finded.top + finded.height - region.top;
+                        } else {
+                            newSize.height = size.height;
+                        }
+                    }
+                } else {
+                    newSize.height = size.height;
+                }
+                return newSize;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                return size;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                return size;
+        }
+    },
+
+    _getScrollOffset: function () {
+        return this.arrangement._getScrollOffset();
+    },
+
+    _setLayoutType: function (type) {
+        try {
+            //BI.nextTick(function () {
+            switch (type) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "");
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "-1");
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    $(">.ui-resizable-s", this.arrangement.container.element).css("zIndex", "-1");
+                    break;
+            }
+            this.arrangement.container.element.resizable("option", "disabled", type === BI.Arrangement.LAYOUT_TYPE.FREE);
+            //});
+        } catch (e) {
+
+        }
+    },
+
+    getClientWidth: function () {
+        return this.arrangement.getClientWidth();
+    },
+
+    getClientHeight: function () {
+        return this.arrangement.getClientHeight();
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        return this.arrangement.getDirectRelativeRegions(name, direction);
+    },
+
+    addRegion: function (region, position) {
+        this._initResizable(region.el);
+        var self = this, flag;
+        var old = this.arrangement.getAllRegions();
+        if (BI.isNotNull(this.position)) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    var type = this.position.type;
+                    var current = this.position.region;
+                    switch (type) {
+                        case "top-gap":
+                            var t = this.arrangement._getEquivalentRelativeRegions(current.id, ["top"])[0];
+                            current = this.getRegionByName(t.id);
+                            break;
+                        case "bottom-gap":
+                            break;
+                    }
+                    var id = BI.UUID();
+                    var insert = this.position.insert;
+                    if (insert.height > 0) {
+                        var clone = this.arrangement._cloneRegion();
+                        //找到最下面的组件
+                        var occupied = this.arrangement._getRegionOccupied();
+                        var bottomRegions = [];
+                        BI.each(clone, function (i, region) {
+                            if (self.arrangement._isEqual(region.top + region.height, occupied.top + occupied.height)) {
+                                bottomRegions.push(region);
+                            }
+                        });
+                        var bs = this.arrangement._getInDirectRelativeRegions(current.id, ["bottom"]).bottom;
+                        var seen = [current.id];
+                        var bottoms = bs.bottom;
+                        var occ = this.arrangement._getRegionOccupied(bottoms);
+                        clone[id] = BI.extend({}, region, {
+                            left: occ.left,
+                            width: occ.width,
+                            top: current.top + current.height,
+                            height: insert.height
+                        });
+                        while (bottoms.length > 0) {
+                            BI.each(bottoms, function (i, bottom) {
+                                seen.push(bottom.id);
+                                var r = self.getRegionByName(bottom.id);
+                                BI.extend(clone[bottom.id], {
+                                    top: r.top + insert.height
+                                });
+                            });
+                            var t = [];
+                            BI.each(bottoms, function (i, bottom) {
+                                var n = self.arrangement._getInDirectRelativeRegions(bottom.id, ["bottom"]).bottom;
+                                BI.each(n.top, function (i, region) {
+                                    if (!seen.contains(region.id)) {
+                                        seen.push(region.id);
+                                        var r = self.getRegionByName(region.id);
+                                        BI.extend(clone[region.id], {
+                                            height: r.height + insert.height
+                                        });
+                                    }
+                                });
+                                t = t.concat(n.bottom);
+                            });
+                            t = BI.uniq(t, function (i, region) {
+                                return region.id;
+                            });
+                            bottoms = t;
+                        }
+                        BI.each(bottomRegions, function (i, region) {
+                            if (!seen.contains(region.id)) {
+                                region.height = region.height + insert.height;
+                            }
+                        });
+                        this.arrangement.populate(BI.toArray(clone));
+                        this.arrangement.resize();
+                        flag = true;
+                    }
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+            this.position = null;
+        } else {
+            if (flag = this.arrangement.addRegion(region, position)) {
+                this._old = old;
+            }
+        }
+        return flag;
+    },
+
+    deleteRegion: function (name) {
+        var flag;
+        var old = this.getAllRegions();
+        if (flag = this.arrangement.deleteRegion(name)) {
+            this._old = old;
+        } else {
+            this._old = this.getAllRegions();
+            this.relayout();
+        }
+        return true;
+    },
+
+    setRegionSize: function (name, size) {
+        var flag;
+        var old = this.getAllRegions();
+        size = this._checkRegionSize(name, size);
+        if (flag = this.arrangement.setRegionSize(name, size)) {
+            this._old = old;
+        }
+        return flag;
+    },
+
+    setPosition: function (position, size) {
+        var self = this;
+        var at = this.arrangement.setPosition(position, size);
+        this.position = null;
+        if (!at) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    if (position.left < 0 || position.top < 0) {
+                        return null;
+                    }
+                    var offset = this.arrangement._getScrollOffset();
+                    position = {
+                        left: position.left + offset.left,
+                        top: position.top + offset.top
+                    };
+                    BI.some(this.getAllRegions(), function (id, region) {
+                        if (self.arrangement._isPositionInBounds(position, region)) {
+                            var at = self.arrangement._positionAt(position, region);
+                            if (at.type === "top-gap" || at.type === "bottom-gap") {
+                                self.arrangement._setArrangeSize({
+                                    top: region.top - 8 + (at.type === "bottom-gap" ? region.height : 0),
+                                    left: region.left,
+                                    width: region.width,
+                                    height: 16
+                                });
+                                self.position = {
+                                    insert: {
+                                        height: (size || {}).height
+                                    },
+                                    type: at.type,
+                                    region: region
+                                };
+                                self.arrangement._start();
+                            }
+                            return true;
+                        }
+                    });
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        return this.position || at;
+    },
+
+    setRegionPosition: function (name, position) {
+        var region = this.getRegionByName(name);
+        region.el.element.css("zIndex", ++this.zIndex);
+        return this.arrangement.setRegionPosition(name, position);
+    },
+
+    zoom: function (ratio) {
+        this.arrangement.zoom(ratio);
+    },
+
+    resize: function () {
+        this.arrangement.resize();
+    },
+
+    relayout: function () {
+        return this.arrangement.relayout();
+    },
+
+    setLayoutType: function (type) {
+        var self = this;
+        this._setLayoutType(type);
+        this.arrangement.setLayoutType(type);
+    },
+
+    getLayoutType: function () {
+        return this.arrangement.getLayoutType();
+    },
+
+    getLayoutRatio: function () {
+        return this.arrangement.getLayoutRatio();
+    },
+
+    getHelper: function () {
+        return this.arrangement.getHelper();
+    },
+
+    getRegionByName: function (name) {
+        return this.arrangement.getRegionByName(name);
+    },
+
+    getAllRegions: function () {
+        return this.arrangement.getAllRegions();
+    },
+
+    revoke: function () {
+        if (this._old) {
+            this.populate(BI.toArray(this._old));
+        }
+    },
+
+    populate: function (items) {
+        var self = this;
+        BI.each(items, function (i, item) {
+            self._initResizable(item.el);
+        });
+        this.arrangement.populate(items);
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                BI.nextTick(function () {
+                    self.arrangement.resize();
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+    }
+});
+BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE";
+BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_RESIZE";
+BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE";
+BI.AdaptiveArrangement.EVENT_RESIZE = "AdaptiveArrangement.EVENT_RESIZE";
+$.shortcut('bi.adaptive_arrangement', BI.AdaptiveArrangement);
\ No newline at end of file
diff --git a/src/widget/arrangement/arrangement.block.js b/src/widget/arrangement/arrangement.block.js
new file mode 100644
index 000000000..cbdac2de2
--- /dev/null
+++ b/src/widget/arrangement/arrangement.block.js
@@ -0,0 +1,22 @@
+/**
+ * Arrangement的block面板
+ *
+ * Created by GUY on 2016/3/1.
+ * @class BI.ArrangementBlock
+ * @extends BI.Widget
+ */
+BI.ArrangementBlock = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ArrangementBlock.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement-block"
+        });
+    },
+
+    _init: function () {
+        BI.ArrangementBlock.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        
+    }
+});
+$.shortcut('bi.arrangement_block', BI.ArrangementBlock);
\ No newline at end of file
diff --git a/src/widget/arrangement/arrangement.droppable.js b/src/widget/arrangement/arrangement.droppable.js
new file mode 100644
index 000000000..c54914aff
--- /dev/null
+++ b/src/widget/arrangement/arrangement.droppable.js
@@ -0,0 +1,22 @@
+/**
+ * Arrangement的drop面板
+ *
+ * Created by GUY on 2016/3/1.
+ * @class BI.ArrangementDroppable
+ * @extends BI.Widget
+ */
+BI.ArrangementDroppable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ArrangementDroppable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement-droppable"
+        });
+    },
+
+    _init: function () {
+        BI.ArrangementDroppable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        
+    }
+});
+$.shortcut('bi.arrangement_droppable', BI.ArrangementDroppable);
\ No newline at end of file
diff --git a/src/widget/arrangement/arrangement.js b/src/widget/arrangement/arrangement.js
new file mode 100644
index 000000000..713876f45
--- /dev/null
+++ b/src/widget/arrangement/arrangement.js
@@ -0,0 +1,2893 @@
+/**
+ * 布局
+ *
+ * Created by GUY on 2016/2/23.
+ * @class BI.Arrangement
+ * @extends BI.Widget
+ */
+BI.Arrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Arrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-arrangement",
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            isNeedReLayout: true,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.Arrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.arrangement_droppable",
+            cls: "arrangement-block",
+            invisible: true
+        });
+        this.block = BI.createWidget({
+            type: "bi.arrangement_block",
+            invisible: true
+        });
+        this.droppable = BI.createWidget({
+            type: "bi.layout",
+            cls: "arrangement-drop-container",
+            invisible: true
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            items: o.items.concat([this.block, this.arrangement, {
+                el: this.droppable,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }])
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.adaptive",
+            width: "100%",
+            height: "100%",
+            scrollable: true,
+            items: [this.container]
+        });
+
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: this,
+            items: [this.scrollContainer]
+        });
+        this.regions = {};
+        this.locations = {};
+        this.drops = {};
+        this.storeDrops = {};
+        if (o.items.length > 0) {
+            BI.nextTick(function () {
+                self.populate(o.items);
+            });
+        }
+    },
+
+    ////初始化操作////
+    _calculateRegions: function (items) {
+        var self = this, o = this.options;
+        this.regions = {};
+        this.drops = {};
+        BI.each(items, function (i, item) {
+            var region = self._createOneRegion(item);
+            self.regions[region.id] = region;
+            var drop = self._createOneDrop(region);
+            self.drops[drop.id] = drop;
+            self.storeDrops[drop.id] = drop;
+        });
+    },
+
+    //定方位
+    _locationRegion: function () {
+        var self = this, o = this.options;
+        this.locations = {};
+        var reg = [];
+        BI.each(this.regions, function (id, region) {
+            var t = new BI.Region(region.left, region.top, region.width, region.height);
+            t.id = id;
+            reg.push(t);
+            self.locations[id] = {top: [], left: [], right: [], bottom: []};
+        });
+        BI.each(reg, function (i, dim) {
+            var topRegion = new BI.Region(dim.x, 0, dim.w, dim.y),
+                bottomRegion = new BI.Region(dim.x, dim.y + dim.h, dim.w, BI.MAX),
+                leftRegion = new BI.Region(0, dim.y, dim.x, dim.h),
+                rightRegion = new BI.Region(dim.x + dim.w, dim.y, BI.MAX, dim.h);
+            BI.each(reg, function (j, tar) {
+                if (i !== j) {
+                    if (tar.isIntersects(topRegion) && self._isLessThanEqual(tar.y + tar.h, dim.y)) {
+                        self.locations[dim.id].top.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(bottomRegion) && self._isMoreThanEqual(tar.y, dim.y + dim.h)) {
+                        self.locations[dim.id].bottom.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(leftRegion) && self._isLessThanEqual(tar.x + tar.w, dim.x)) {
+                        self.locations[dim.id].left.push(self.regions[tar.id]);
+                    }
+                    if (tar.isIntersects(rightRegion) && self._isMoreThanEqual(tar.x, dim.x + dim.w)) {
+                        self.locations[dim.id].right.push(self.regions[tar.id]);
+                    }
+                }
+            });
+        });
+    },
+
+    _isEqual: function (num1, num2) {
+        return Math.abs(num1 - num2) < 2;
+    },
+
+    _isLessThan: function (num1, num2) {
+        return num1 < num2 && !this._isEqual(num1, num2);
+    },
+
+    _isMoreThan: function (num1, num2) {
+        return num1 > num2 && !this._isEqual(num1, num2);
+    },
+
+    _isLessThanEqual: function (num1, num2) {
+        return num1 <= num2 || this._isEqual(num1, num2);
+    },
+
+    _isMoreThanEqual: function (num1, num2) {
+        return num1 >= num2 || this._isEqual(num1, num2);
+    },
+
+    ////方法////
+    _isPositionInBounds: function (position, bound) {
+        var region = new BI.Region(bound.left, bound.top, bound.width, bound.height);
+        return region.isPointInside(position.left, position.top);
+    },
+
+    //获取某区域等量相关联的区域
+    _getEquivalentRelativeRegions: function (name, direction) {
+        var self = this;
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var result = [];
+        var target = this.regions[name];
+        var tops = this.locations[name].top;
+        var bottoms = this.locations[name].bottom;
+        var lefts = this.locations[name].left;
+        var rights = this.locations[name].right;
+        var finded = direction.contains("top") && BI.some(tops, function (i, region) {
+                if (self._isEqual(region.top + region.height, target.top) && self._isEqual(region.left, target.left) && self._isEqual(region.width, target.width)) {
+                    var clone = BI.clone(region);
+                    clone.height = region.height + target.height;
+                    result.push(clone);
+                    return true;
+                }
+            });
+        if (!finded) {
+            finded = direction.contains("bottom") && BI.some(bottoms, function (i, region) {
+                    if (self._isEqual(target.top + target.height, region.top) && self._isEqual(region.left, target.left) && self._isEqual(region.width, target.width)) {
+                        var clone = BI.clone(region);
+                        clone.top = region.top - target.height;
+                        clone.height = region.height + target.height;
+                        result.push(clone);
+                        return true;
+                    }
+                });
+            if (!finded) {
+                finded = direction.contains("left") && BI.some(lefts, function (i, region) {
+                        if (self._isEqual(region.left + region.width, target.left) && self._isEqual(region.top, target.top) && self._isEqual(region.height, target.height)) {
+                            var clone = BI.clone(region);
+                            clone.width = region.width + target.width;
+                            result.push(clone);
+                            return true;
+                        }
+                    });
+                if (!finded) {
+                    finded = direction.contains("right") && BI.some(rights, function (i, region) {
+                            if (self._isEqual(target.left + target.width, region.left) && self._isEqual(region.top, target.top) && self._isEqual(region.height, target.height)) {
+                                var clone = BI.clone(region);
+                                clone.left = region.left - target.width;
+                                clone.width = region.width + target.width;
+                                result.push(clone);
+                                return true;
+                            }
+                        });
+                    if (!finded) {
+                        var findTopRegions = [], findBottomRegions = [];
+                        direction.contains("top") && BI.each(tops, function (i, region) {
+                            if (self._isEqual(region.top + region.height, target.top)
+                                && self._isMoreThanEqual(region.left, target.left)
+                                && self._isLessThanEqual(region.left + region.width, target.left + target.width)) {
+                                findTopRegions.push(region);
+                            }
+                        });
+                        direction.contains("bottom") && BI.each(bottoms, function (i, region) {
+                            if (self._isEqual(target.top + target.height, region.top)
+                                && self._isMoreThanEqual(region.left, target.left)
+                                && self._isLessThanEqual(region.left + region.width, target.left + target.width)) {
+                                findBottomRegions.push(region);
+                            }
+                        });
+                        var topValid = isRegionsValid(findTopRegions, "top"), bottomValid = isRegionsValid(findBottomRegions, "bottom");
+                        if (topValid && bottomValid) {
+                            BI.each(findTopRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.height = region.height + target.height / 2;
+                                result.push(clone);
+                            });
+                            BI.each(findBottomRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.top = region.top - target.height / 2;
+                                clone.height = region.height + target.height / 2;
+                                result.push(clone);
+                            });
+                        } else if (topValid) {
+                            BI.each(findTopRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.height = region.height + target.height;
+                                result.push(clone);
+                            });
+                        } else if (bottomValid) {
+                            BI.each(findBottomRegions, function (i, region) {
+                                var clone = BI.clone(region);
+                                clone.top = region.top - target.height;
+                                clone.height = region.height + target.height;
+                                result.push(clone);
+                            });
+                        }
+                        if (!topValid && !bottomValid) {
+                            var findLeftRegions = [], findRightRegions = [];
+                            direction.contains("left") && BI.each(lefts, function (i, region) {
+                                if (self._isEqual(region.left + region.width, target.left)
+                                    && self._isMoreThanEqual(region.top, target.top)
+                                    && self._isLessThanEqual(region.top + region.height, target.top + target.height)) {
+                                    findLeftRegions.push(region);
+                                }
+                            });
+                            direction.contains("right") && BI.each(rights, function (i, region) {
+                                if (self._isEqual(target.left + target.width, region.left)
+                                    && self._isMoreThanEqual(region.top, target.top)
+                                    && self._isLessThanEqual(region.top + region.height, target.top + target.height)) {
+                                    findRightRegions.push(region);
+                                }
+                            });
+                            var leftValid = isRegionsValid(findLeftRegions, "left"), rightValid = isRegionsValid(findRightRegions, "right");
+                            if (leftValid && rightValid) {
+                                BI.each(findLeftRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.width = region.width + target.width / 2;
+                                    result.push(clone);
+                                });
+                                BI.each(findRightRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.left = region.left - target.width / 2;
+                                    clone.width = region.width + target.width / 2;
+                                    result.push(clone);
+                                });
+                            } else if (leftValid) {
+                                BI.each(findLeftRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.width = region.width + target.width;
+                                    result.push(clone);
+                                });
+                            } else if (rightValid) {
+                                BI.each(findRightRegions, function (i, region) {
+                                    var clone = BI.clone(region);
+                                    clone.left = region.left - target.width;
+                                    clone.width = region.width + target.width;
+                                    result.push(clone);
+                                });
+                            }
+
+                            //上下左右都不可行
+                            if (!leftValid && !rightValid) {
+
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+        function isRegionsValid(regions, dir) {
+            var occupied = self._getRegionOccupied(regions);
+            switch (dir) {
+                case "top":
+                case "bottom":
+                    return self._isEqual(occupied.left, target.left) && self._isEqual(occupied.width, target.width);
+                case "left":
+                case "right":
+                    return self._isEqual(occupied.top, target.top) && self._isEqual(occupied.height, target.height);
+            }
+            return false;
+        }
+    },
+
+    //获取某区域直接相关联的区域
+    _getDirectRelativeRegions: function (name, direction) {
+        var self = this;
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var result = [];
+        var target = this.regions[name];
+        var tops = this.locations[name].top;
+        var bottoms = this.locations[name].bottom;
+        var lefts = this.locations[name].left;
+        var rights = this.locations[name].right;
+        var finded = direction.contains("top") && BI.some(tops, function (i, region) {
+                if (self._isEqual(region.top + region.height, target.top)
+                    && ((self._isMoreThanEqual(region.left, target.left) && self._isLessThan(region.left, target.left + target.width))
+                    || (self._isMoreThan(region.left + region.width, target.left) && self._isLessThanEqual(region.left + region.width, target.left + target.width))
+                    || (self._isLessThan(region.left, target.left) && self._isMoreThan(region.left + region.width, target.left + target.width)))) {
+                    var clone = BI.clone(region);
+                    clone.height = region.height + target.height;
+                    result.push(clone);
+                }
+            });
+        if (!finded) {
+            finded = direction.contains("bottom") && BI.some(bottoms, function (i, region) {
+                    if (self._isEqual(target.top + target.height, region.top)
+                        && ((self._isMoreThanEqual(region.left, target.left) && self._isLessThan(region.left, target.left + target.width))
+                        || (self._isMoreThan(region.left + region.width, target.left) && self._isLessThanEqual(region.left + region.width, target.left + target.width))
+                        || (self._isLessThan(region.left, target.left) && self._isMoreThan(region.left + region.width, target.left + target.width)))) {
+                        var clone = BI.clone(region);
+                        clone.top = region.top - target.height;
+                        clone.height = region.height + target.height;
+                        result.push(clone);
+                    }
+                });
+            if (!finded) {
+                finded = direction.contains("left") && BI.some(lefts, function (i, region) {
+                        if (self._isEqual(region.left + region.width, target.left)
+                            && ((self._isMoreThanEqual(region.top, target.top) && self._isLessThan(region.top, target.top + target.height))
+                            || (self._isMoreThan(region.top + region.height, target.top) && self._isLessThanEqual(region.top + region.height, target.top + target.height))
+                            || (self._isLessThan(region.top, target.top) && self._isMoreThan(region.top + region.height, target.top + target.height)))) {
+                            var clone = BI.clone(region);
+                            clone.width = region.width + target.width;
+                            result.push(clone);
+                        }
+                    });
+                if (!finded) {
+                    finded = direction.contains("right") && BI.some(rights, function (i, region) {
+                            if (self._isEqual(target.left + target.width, region.left)
+                                && ((self._isMoreThanEqual(region.top, target.top) && self._isLessThan(region.top, target.top + target.height))
+                                || (self._isMoreThan(region.top + region.height, target.top) && self._isLessThanEqual(region.top + region.height, target.top + target.height))
+                                || (self._isLessThan(region.top, target.top) && self._isMoreThan(region.top + region.height, target.top + target.height)))) {
+                                var clone = BI.clone(region);
+                                clone.left = region.left - target.width;
+                                clone.width = region.width + target.width;
+                                result.push(clone);
+                            }
+                        });
+                }
+            }
+        }
+        return result;
+    },
+
+    //获取间接相关联的区域,即调整name区域后需要附带调整的所有相关区域(包括自身)
+    _getInDirectRelativeRegions: function (name, direction) {
+        var self = this, dict = ["top", "left", "right", "bottom"];
+        var result = {};
+        direction || (direction = dict);
+        function recursion(regions, dir, store, cache) {
+            BI.each(regions, function (i, region) {
+                if (cache[region.id]) {
+                    return;
+                }
+                cache[region.id] = true;
+                if (!store[dict[3 - dir]]) {
+                    store[dict[3 - dir]] = [];
+                }
+                store[dict[3 - dir]].push(region);
+                recursion(self._getDirectRelativeRegions(region.id, [dict[dir]]), 3 - dir, store, cache);
+            })
+        }
+
+        if (direction.contains("top")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("top"), store, cache);
+            store["top"] = BI.sortBy(store["top"], "left");
+            store["bottom"] = BI.sortBy(store["bottom"], "left");
+            result["top"] = store;
+        }
+        if (direction.contains("bottom")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("bottom"), store, cache);
+            store["top"] = BI.sortBy(store["top"], "left");
+            store["bottom"] = BI.sortBy(store["bottom"], "left");
+            result["bottom"] = store;
+        }
+        if (direction.contains("left")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("left"), store, cache);
+            store["left"] = BI.sortBy(store["left"], "top");
+            store["right"] = BI.sortBy(store["right"], "top");
+            result["left"] = store;
+        }
+        if (direction.contains("right")) {
+            var store = {}, cache = {};
+            recursion([this.regions[name]], dict.indexOf("right"), store, cache);
+            store["left"] = BI.sortBy(store["left"], "top");
+            store["right"] = BI.sortBy(store["right"], "top");
+            result["right"] = store;
+        }
+        return result;
+    },
+
+    _getLeftAlignRegions: function (name) {
+        var self = this;
+        var tops = this._getDirectRelativeRegions(name, ["top"]);
+        var bottoms = this._getDirectRelativeRegions(name, ["bottom"]);
+        var current = this.regions[name];
+        var rtop = [], rbottom = [];
+        BI.each(tops, function (i, region) {
+            if (self._isEqual(region.left, current.left)) {
+                rtop.push(region);
+            }
+        });
+        BI.each(bottoms, function (i, region) {
+            if (self._isEqual(region.left, current.left)) {
+                rbottom.push(region);
+            }
+        });
+        return {
+            top: rtop,
+            bottom: rbottom
+        }
+    },
+
+    _getRightAlignRegions: function (name) {
+        var self = this;
+        var tops = this._getDirectRelativeRegions(name, ["top"]);
+        var bottoms = this._getDirectRelativeRegions(name, ["bottom"]);
+        var current = this.regions[name];
+        var rtop = [], rbottom = [];
+        BI.each(tops, function (i, region) {
+            if (self._isEqual(region.left + region.width, current.left + current.width)) {
+                rtop.push(region);
+            }
+        });
+        BI.each(bottoms, function (i, region) {
+            if (self._isEqual(region.left + region.width, current.left + current.width)) {
+                rbottom.push(region);
+            }
+        });
+        return {
+            top: rtop,
+            bottom: rbottom
+        }
+    },
+
+    _getTopAlignRegions: function (name) {
+        var self = this;
+        var lefts = this._getDirectRelativeRegions(name, ["left"]);
+        var rights = this._getDirectRelativeRegions(name, ["right"]);
+        var current = this.regions[name];
+        var rleft = [], rright = [];
+        BI.each(lefts, function (i, region) {
+            if (self._isEqual(region.top, current.top)) {
+                rleft.push(region);
+            }
+        });
+        BI.each(rights, function (i, region) {
+            if (self._isEqual(region.top, current.top)) {
+                rright.push(region);
+            }
+        });
+        return {
+            left: rleft,
+            right: rright
+        }
+    },
+
+    _getBottomAlignRegions: function (name) {
+        var self = this;
+        var lefts = this._getDirectRelativeRegions(name, ["left"]);
+        var rights = this._getDirectRelativeRegions(name, ["right"]);
+        var current = this.regions[name];
+        var rleft = [], rright = [];
+        BI.each(lefts, function (i, region) {
+            if (self._isEqual(region.top + region.height, current.top + current.height)) {
+                rleft.push(region);
+            }
+        });
+        BI.each(rights, function (i, region) {
+            if (self._isEqual(region.top + region.height, current.top + current.height)) {
+                rright.push(region);
+            }
+        });
+        return {
+            left: rleft,
+            right: rright
+        }
+    },
+
+    //获取占有的最大Region
+    _getRegionOccupied: function (regions) {
+        var self = this, o = this.options;
+        if (BI.size(regions || this.regions) <= 0) {
+            return {
+                left: 0,
+                top: 0,
+                width: 0,
+                height: 0
+            }
+        }
+        var minLeft = BI.MAX, maxLeft = BI.MIN, minTop = BI.MAX, maxTop = BI.MIN;
+        BI.each(regions || this.regions, function (id, region) {
+            minLeft = Math.min(minLeft, region.left);
+            maxLeft = Math.max(maxLeft, region.left + region.width);
+            minTop = Math.min(minTop, region.top);
+            maxTop = Math.max(maxTop, region.top + region.height);
+        });
+        return {
+            left: minLeft,
+            top: minTop,
+            width: maxLeft - minLeft,
+            height: maxTop - minTop
+        }
+    },
+
+    //两个区域的交叉面积
+    _getCrossArea: function (region1, region2) {
+        if (region1.left <= region2.left) {
+            if (region1.top <= region2.top) {
+                if (region1.top + region1.height > region2.top && region1.left + region1.width > region2.left) {
+                    if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region1.left + region1.width, region2.left)) {
+                        return 0;
+                    }
+                    return (region1.top + region1.height - region2.top) * (region1.left + region1.width - region2.left);
+                }
+            } else {
+                if (region2.top + region2.height > region1.top && region1.left + region1.width > region2.left) {
+                    if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region1.left + region1.width, region2.left)) {
+                        return 0;
+                    }
+                    return (region2.top + region2.height - region1.top) * (region1.left + region1.width - region2.left);
+                }
+            }
+        } else {
+            if (region1.top <= region2.top) {
+                if (region1.top + region1.height > region2.top && region2.left + region2.width > region1.left) {
+                    if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region2.left + region2.width, region1.left)) {
+                        return 0;
+                    }
+                    return (region1.top + region1.height - region2.top) * (region2.left + region2.width - region1.left);
+                }
+            } else {
+                if (region2.top + region2.height > region1.top && region2.left + region2.width > region1.left) {
+                    if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region2.left + region2.width, region1.left)) {
+                        return 0;
+                    }
+                    return (region2.top + region2.height - region1.top) * (region2.left + region2.width - region1.left);
+                }
+            }
+        }
+        return 0;
+    },
+
+    //是否有覆盖的组件
+    _isRegionOverlay: function (regions) {
+        var reg = [];
+        BI.each(regions || this.regions, function (id, region) {
+            reg.push(new BI.Region(region.left, region.top, region.width, region.height));
+        });
+        for (var i = 0, len = reg.length; i < len; i++) {
+            for (var j = i + 1; j < len; j++) {
+                var area1 = {
+                    left: reg[i].x,
+                    top: reg[i].y,
+                    width: reg[i].w,
+                    height: reg[i].h
+                };
+                var area2 = {
+                    left: reg[j].x,
+                    top: reg[j].y,
+                    width: reg[j].w,
+                    height: reg[j].h
+                };
+                if (reg[i].isIntersects(reg[j]) && this._getCrossArea(area1, area2) > 1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    },
+
+    //布局是否是优良的
+    _isArrangeFine: function (regions) {
+        switch (this.options.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isRegionOverlay()) {
+                    return false;
+                }
+                var maxRegion = this._getRegionOccupied(regions);
+                var area = maxRegion.width * maxRegion.height;
+                var all = 0;
+                BI.each(regions || this.regions, function (id, region) {
+                    all += region.width * region.height;
+                });
+                return Math.abs(area - all) < 8;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (this._isRegionOverlay()) {
+                    return false;
+                }
+        }
+        return true;
+    },
+
+    _getRegionNames: function (regions) {
+        var names = [];
+        BI.each(regions || this.regions, function (i, region) {
+            names.push(region.id || region.attr("id"));
+        });
+        return names;
+    },
+
+    _getRegionsByNames: function (names, regions) {
+        names = BI.isArray(names) ? names : [names];
+        regions = regions || this.regions;
+        if (BI.isArray(regions)) {
+            var result = [];
+            BI.each(regions, function (i, region) {
+                if (names.contains(region.id || region.attr("id"))) {
+                    result.push(region);
+                }
+            });
+        } else {
+            var result = {};
+            BI.each(names, function (i, name) {
+                result[name] = regions[name];
+            });
+        }
+        return result;
+    },
+
+    _cloneRegion: function (regions) {
+        var clone = {};
+        BI.each(regions || this.regions, function (id, region) {
+            clone[id] = {};
+            clone[id].el = region.el;
+            clone[id].id = region.id;
+            clone[id].left = region.left;
+            clone[id].top = region.top;
+            clone[id].width = region.width;
+            clone[id].height = region.height;
+        });
+        return clone;
+    },
+
+    //测试合法性
+    _test: function (regions) {
+        var self = this;
+        return !BI.any(regions || this.regions, function (i, region) {
+            if (BI.isNaN(region.width) || BI.isNaN(region.height) || region.width <= 21 || region.height <= 21) {
+                return true;
+            }
+        })
+    },
+
+    //对区域进行划分
+    _splitRegions: function (name) {
+        var result = [];
+        var tid = BI.UUID();
+        var _left = this._getLeftAlignRegions(name);
+        var _right = this._getRightAlignRegions(name);
+        var _top = this._getTopAlignRegions(name);
+        var _bottom = this._getBottomAlignRegions(name);
+        if (_left.top.length > 0) {
+            var upid = _left.top[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[upid].width) / 2;//两个组件中较小宽度的一半
+            var left = (clone[name].left + clone[upid].left) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: left,
+                top: clone[upid].top,
+                width: split,
+                height: clone[name].height + clone[upid].height
+            };
+            BI.extend(clone[name], {
+                left: left + split,
+                width: clone[name].width - split - (left - clone[name].left)
+            });
+            BI.extend(clone[upid], {
+                left: left + split,
+                width: clone[upid].width - split - (left - clone[upid].left)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "left-top",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_left.bottom.length > 0) {
+            var bottomid = _left.bottom[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[bottomid].width) / 2;
+            var left = (clone[name].left + clone[bottomid].left) / 2;
+            var insert = clone[tid] = {//新增的区域
+                left: left,
+                top: clone[name].top,
+                width: split,
+                height: clone[name].height + clone[bottomid].height
+            };
+            BI.extend(clone[name], {
+                left: left + split,
+                width: clone[name].width - split - (left - clone[name].left)
+            });
+            BI.extend(clone[bottomid], {
+                left: left + split,
+                width: clone[bottomid].width - split - (left - clone[bottomid].left)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-left",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_right.top.length > 0) {
+            var upid = _right.top[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[upid].width) / 2;//两个组件中较小宽度的一半
+            var right = (clone[name].left + clone[name].width + clone[upid].left + clone[upid].width) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: right - split,
+                top: clone[upid].top,
+                width: split,
+                height: clone[name].height + clone[upid].height
+            };
+            BI.extend(clone[name], {
+                width: right - clone[name].left - split
+            });
+            BI.extend(clone[upid], {
+                width: right - clone[upid].left - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-right",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_right.bottom.length > 0) {
+            var bottomid = _right.bottom[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].width, clone[bottomid].width) / 2;//两个组件中较小宽度的一半
+            var right = (clone[name].left + clone[name].width + clone[bottomid].left + clone[bottomid].width) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: right - split,
+                top: clone[name].top,
+                width: split,
+                height: clone[name].height + clone[bottomid].height
+            };
+            BI.extend(clone[name], {
+                width: right - clone[name].left - split
+            });
+            BI.extend(clone[bottomid], {
+                width: right - clone[bottomid].left - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-right",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_top.left.length > 0) {
+            var leftid = _top.left[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[leftid].height) / 2;//两个组件中较小高度的一半
+            var top = (clone[name].top + clone[leftid].top) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                top: top,
+                left: clone[leftid].left,
+                height: split,
+                width: clone[name].width + clone[leftid].width
+            };
+            BI.extend(clone[name], {
+                top: top + split,
+                height: clone[name].height - split - (top - clone[name].top)
+            });
+            BI.extend(clone[leftid], {
+                top: top + split,
+                height: clone[leftid].height - split - (top - clone[leftid].top)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-left",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_top.right.length > 0) {
+            var rightid = _top.right[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[rightid].height) / 2;//两个组件中较小高度的一半
+            var top = (clone[name].top + clone[rightid].top) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                top: top,
+                left: clone[name].left,
+                height: split,
+                width: clone[name].width + clone[rightid].width
+            };
+            BI.extend(clone[name], {
+                top: top + split,
+                height: clone[name].height - split - (top - clone[name].top)
+            });
+            BI.extend(clone[rightid], {
+                top: top + split,
+                height: clone[rightid].height - split - (top - clone[rightid].top)
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "top-right-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_bottom.left.length > 0) {
+            var leftid = _bottom.left[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[leftid].height) / 2;//两个组件中较小高度的一半
+            var bottom = (clone[name].top + clone[name].height + clone[leftid].top + clone[leftid].height) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: clone[leftid].left,
+                top: bottom - split,
+                height: split,
+                width: clone[name].width + clone[leftid].width
+            };
+            BI.extend(clone[name], {
+                height: bottom - clone[name].top - split
+            });
+            BI.extend(clone[leftid], {
+                height: bottom - clone[leftid].top - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-left-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        if (_bottom.right.length > 0) {
+            var rightid = _bottom.right[0].id;
+            var tid = BI.UUID();
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var split = Math.min(clone[name].height, clone[rightid].height) / 2;//两个组件中较小高度的一半
+            var bottom = (clone[name].top + clone[name].height + clone[rightid].top + clone[rightid].height) / 2;//求平均,减少误差
+            var insert = clone[tid] = {//新增的区域
+                left: clone[name].left,
+                top: bottom - split,
+                height: split,
+                width: clone[name].width + clone[rightid].width
+            };
+            BI.extend(clone[name], {
+                height: bottom - clone[name].top - split
+            });
+            BI.extend(clone[rightid], {
+                height: bottom - clone[rightid].top - split
+            });
+            if (this._test(clone)) {
+                delete clone[tid];
+                result.push({
+                    type: "bottom-right-second",
+                    regions: clone,
+                    insert: insert
+                });
+            }
+        }
+        //有上方居中drop
+        var lefts = _top.left, rights = _top.right;
+        if (lefts.length > 0 && rights.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (lefts.length > 0 || rights.length > 0) {
+                var clone = this._cloneRegion();
+                if (lefts.length > 0) {
+                    store.push(this.regions[lefts[0].id]);
+                }
+                if (rights.length > 0) {
+                    store.push(this.regions[rights[0].id]);
+                }
+                count++;
+                var top = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.top;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.height;
+                    }).height / 2;
+                var insert = clone[tid] = {
+                    left: occupied.left,
+                    width: occupied.width,
+                    top: top,
+                    height: split
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        top: top + split,
+                        height: region.height - split - (top - region.top)
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "top-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (lefts.length > 0) lefts = this._getTopAlignRegions(lefts[0].id).left;
+                if (rights.length > 0) rights = this._getTopAlignRegions(rights[0].id).right;
+            }
+        }
+        //有下方居中drop
+        var lefts = _bottom.left, rights = _bottom.right;
+        if (lefts.length > 0 && rights.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (lefts.length > 0 || rights.length > 0) {
+                var clone = this._cloneRegion();
+                if (lefts.length > 0) {
+                    store.push(this.regions[lefts[0].id]);
+                }
+                if (rights.length > 0) {
+                    store.push(this.regions[rights[0].id]);
+                }
+                count++;
+                var bottom = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.top + r.height;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.height;
+                    }).height / 2;
+                var insert = clone[tid] = {
+                    left: occupied.left,
+                    width: occupied.width,
+                    top: bottom - split,
+                    height: split
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        height: bottom - region.top - split
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "bottom-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (lefts.length > 0) lefts = this._getBottomAlignRegions(lefts[0].id).left;
+                if (rights.length > 0) rights = this._getBottomAlignRegions(rights[0].id).right;
+            }
+        }
+        //有左方居中drop
+        var tops = _left.top, bottoms = _left.bottom;
+        if (tops.length > 0 && bottoms.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (tops.length > 0 || bottoms.length > 0) {
+                var clone = this._cloneRegion();
+                if (tops.length > 0) {
+                    store.push(this.regions[tops[0].id]);
+                }
+                if (bottoms.length > 0) {
+                    store.push(this.regions[bottoms[0].id]);
+                }
+                count++;
+                var left = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.left;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.width;
+                    }).width / 2;
+                var insert = clone[tid] = {
+                    left: left,
+                    width: split,
+                    top: occupied.top,
+                    height: occupied.height
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        left: left + split,
+                        width: region.width - split - (left - region.left)
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "left-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (tops.length > 0) tops = this._getLeftAlignRegions(tops[0].id).top;
+                if (bottoms.length > 0) bottoms = this._getLeftAlignRegions(bottoms[0].id).bottom;
+            }
+        }
+        //有右方居中drop
+        var tops = _right.top, bottoms = _right.bottom;
+        if (tops.length > 0 && bottoms.length > 0) {
+            var count = 0;
+            var store = [this.regions[name]];
+            while (tops.length > 0 || bottoms.length > 0) {
+                var clone = this._cloneRegion();
+                if (tops.length > 0) {
+                    store.push(this.regions[tops[0].id]);
+                }
+                if (bottoms.length > 0) {
+                    store.push(this.regions[bottoms[0].id]);
+                }
+                count++;
+                var right = BI.average(store, function (i, r) {//求平均,减少误差
+                    return r.left + r.width;
+                });
+                var occupied = this._getRegionOccupied(store);
+
+                var split = BI.min(store, function (i, r) {
+                        return r.width;
+                    }).width / 2;
+                var insert = clone[tid] = {
+                    left: right - split,
+                    width: split,
+                    top: occupied.top,
+                    height: occupied.height
+                };
+                BI.each(store, function (i, region) {
+                    BI.extend(clone[region.id], {
+                        width: right - region.left - split
+                    });
+                });
+                if (this._test(store)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "right-center" + count,
+                        regions: clone,
+                        insert: insert
+                    });
+                } else {
+                    break;
+                }
+
+                if (tops.length > 0) tops = this._getRightAlignRegions(tops[0].id).top;
+                if (bottoms.length > 0) bottoms = this._getRightAlignRegions(bottoms[0].id).bottom;
+            }
+        }
+        var lefts = this._getEquivalentRelativeRegions(name, ["left"]);
+        if (lefts.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var left = this.regions[lefts[0].id];
+            var width = left.width;
+            var all = left.width + _cur.width;
+            var ratio = width / all;
+            var split = all / 3;
+            var lleft = width - split * ratio, rleft = _cur.width - split * (1 - ratio);
+            var insert = false;
+            if (lleft <= 21) {
+                rleft = _cur.width - split;
+                if (rleft <= 21) {
+
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left,
+                        width: split,
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left + split,
+                        width: _cur.width - split
+                    });
+                }
+            } else if (rleft <= 21) {
+                lleft = width - split;
+                if (lleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left - split,
+                        width: split,
+                    };
+                    BI.extend(clone[left.id], {
+                        top: left.top,
+                        height: left.height,
+                        left: left.left,
+                        width: left.width - split
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: left.left + lleft,
+                    width: split,
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left + _cur.width - rleft,
+                    width: rleft
+                });
+                BI.extend(clone[left.id], {
+                    top: left.top,
+                    height: left.height,
+                    left: left.left,
+                    width: lleft
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "left-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var rights = this._getEquivalentRelativeRegions(name, ["right"]);
+        if (rights.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var right = this.regions[rights[0].id];
+            var width = right.width;
+            var all = right.width + _cur.width;
+            var ratio = width / all;
+            var split = all / 3;
+            var lleft = _cur.width - split * (1 - ratio), rleft = width - split * ratio;
+            var insert = false;
+            if (lleft <= 21) {
+                rleft = width - split;
+                if (rleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: right.top,
+                        height: right.height,
+                        left: right.left,
+                        width: split
+                    };
+                    BI.extend(clone[right.id], {
+                        top: right.top,
+                        height: right.height,
+                        left: right.left + split,
+                        width: right.width - split
+                    })
+                }
+            } else if (rleft <= 21) {
+                lleft = _cur.width - split;
+                if (lleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left + lleft,
+                        width: split
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height,
+                        left: _cur.left,
+                        width: _cur.width - split
+                    })
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left + lleft,
+                    width: split
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: _cur.height,
+                    left: _cur.left,
+                    width: lleft
+                });
+                BI.extend(clone[right.id], {
+                    top: right.top,
+                    height: right.height,
+                    left: right.left + right.width - rleft,
+                    width: rleft
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "right-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var tops = this._getEquivalentRelativeRegions(name, ["top"]);
+        if (tops.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var top = this.regions[tops[0].id];
+            var height = top.height;
+            var all = top.height + _cur.height;
+            var ratio = height / all;
+            var split = all / 3;
+            var tleft = height - split * ratio, bleft = _cur.height - split * (1 - ratio);
+            var insert = false;
+            if (tleft <= 21) {
+                bleft = _cur.height - split;
+                if (bleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top,
+                        width: _cur.width,
+                        left: _cur.left,
+                        height: split
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top + split,
+                        height: _cur.height - split,
+                        left: _cur.left,
+                        width: _cur.width
+                    });
+                }
+            }
+            if (bleft <= 21) {
+                tleft = height - split;
+                if (tleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top - split,
+                        height: split,
+                        left: _cur.left,
+                        width: _cur.width
+                    };
+                    BI.extend(clone[top.id], {
+                        top: top.top,
+                        height: top.height - split,
+                        left: top.left,
+                        width: top.width
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: top.top + tleft,
+                    height: split,
+                    left: _cur.left,
+                    width: _cur.width
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top + _cur.height - bleft,
+                    height: bleft,
+                    left: _cur.left,
+                    width: _cur.width
+                });
+                BI.extend(clone[top.id], {
+                    top: top.top,
+                    height: tleft,
+                    left: top.left,
+                    width: top.width
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "top-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        var bottoms = this._getEquivalentRelativeRegions(name, ["bottom"]);
+        if (bottoms.length === 1) {
+            var clone = this._cloneRegion();
+            var _cur = clone[name];
+            var bottom = this.regions[bottoms[0].id];
+            var height = bottom.height;
+            var all = bottom.height + _cur.height;
+            var ratio = height / all;
+            var split = all / 3;
+            var tleft = _cur.height - split * (1 - ratio), bleft = height - split * ratio;
+            var insert = false;
+            if (tleft <= 21) {
+                bleft = height - split;
+                if (bleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: bottom.top,
+                        height: bottom.height,
+                        left: bottom.left,
+                        width: split
+                    };
+                    BI.extend(clone[bottom.id], {
+                        top: bottom.top + split,
+                        height: bottom.height - split,
+                        left: bottom.left,
+                        width: bottom.width
+                    });
+                }
+            } else if (bleft <= 21) {
+                tleft = _cur.height - split;
+                if (tleft <= 21) {
+                } else {
+                    insert = clone[tid] = {
+                        top: _cur.top + tleft,
+                        height: split,
+                        left: _cur.left,
+                        width: _cur.width
+                    };
+                    BI.extend(clone[name], {
+                        top: _cur.top,
+                        height: _cur.height - split,
+                        left: _cur.left,
+                        width: _cur.width
+                    });
+                }
+            } else {
+                insert = clone[tid] = {
+                    top: _cur.top + tleft,
+                    height: split,
+                    left: _cur.left,
+                    width: _cur.width,
+                };
+                BI.extend(clone[name], {
+                    top: _cur.top,
+                    height: tleft,
+                    left: _cur.left,
+                    width: _cur.width
+                });
+                BI.extend(clone[bottom.id], {
+                    top: bottom.top + bottom.height - bleft,
+                    height: bleft,
+                    left: bottom.left,
+                    width: bottom.width
+                });
+            }
+            if (insert !== false) {
+                if (this._test(clone)) {
+                    delete clone[tid];
+                    result.push({
+                        type: "bottom-line",
+                        regions: clone,
+                        insert: insert
+                    })
+                }
+            }
+        }
+        if (tops.length >= 1) {
+            result.push({
+                type: "top-gap"
+            });
+        }
+        if (bottoms.length >= 1) {
+            result.push({
+                type: "bottom-gap"
+            });
+        }
+        //上
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2,
+        };
+        BI.extend(clone[name], {
+            top: _cur.top + _cur.height / 2,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "top",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //下
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top + _cur.height / 2,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width,
+            height: _cur.height / 2
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "bottom",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //左
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width / 2,
+            height: _cur.height
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left + _cur.width / 2,
+            width: _cur.width / 2,
+            height: _cur.height
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "left",
+                regions: clone,
+                insert: insert
+            })
+        }
+        //右
+        var clone = this._cloneRegion();
+        var _cur = clone[name];
+        var insert = clone[tid] = {
+            top: _cur.top,
+            left: _cur.left + _cur.width / 2,
+            width: _cur.width / 2,
+            height: _cur.height
+        };
+        BI.extend(clone[name], {
+            top: _cur.top,
+            left: _cur.left,
+            width: _cur.width / 2,
+            height: _cur.height
+        });
+        if (this._test(clone)) {
+            delete clone[tid];
+            result.push({
+                type: "right",
+                regions: clone,
+                insert: insert
+            })
+        }
+        return result;
+    },
+
+    _positionAt: function (position, bound) {
+        var left = position.left - bound.left, top = position.top - bound.top;
+        var right = bound.width - left, bottom = bound.height - top;
+        var halfW = bound.width / 2, halfH = bound.height / 2;
+        if (left < 0 || top < 0 || right < 0 || bottom < 0) {
+            return;
+        }
+        var devides = this._splitRegions(bound.id);
+        var types = [];
+        var result = {};
+        var topcenterCount = 0, bottomcenterCount = 0, leftcenterCount = 0, rightcenterCount = 0;
+        BI.each(devides, function (i, devide) {
+            if (devide.type.indexOf("top-center") > -1) {
+                topcenterCount++;
+            } else if (devide.type.indexOf("bottom-center") > -1) {
+                bottomcenterCount++;
+            } else if (devide.type.indexOf("left-center") > -1) {
+                leftcenterCount++;
+            } else if (devide.type.indexOf("right-center") > -1) {
+                rightcenterCount++;
+            }
+            types.push(devide.type);
+            result[devide.type] = devide;
+        });
+        //drop
+        if (top >= 5 && top <= 15 && left >= 5 && left <= 15 && types.contains("left-top")) {
+            return result["left-top"];
+        }
+        if (top >= 5 && top <= 15 && right >= 5 && right <= 15 && types.contains("top-right")) {
+            return result["top-right"];
+        }
+        if (bottom >= 5 && bottom <= 15 && left >= 5 && left <= 15 && types.contains("bottom-left")) {
+            return result["bottom-left"];
+        }
+        if (bottom >= 5 && bottom <= 15 && right >= 5 && right <= 15 && types.contains("bottom-right")) {
+            return result["bottom-right"];
+        }
+
+        if (top >= 5 && top <= 15 && left >= 25 && left <= 35 && types.contains("top-left")) {
+            return result["top-left"];
+        }
+        if (top >= 5 && top <= 15 && right >= 25 && right <= 35 && types.contains("top-right-second")) {
+            return result["top-right-second"];
+        }
+        if (bottom >= 5 && bottom <= 15 && left >= 25 && left <= 35 && types.contains("bottom-left-second")) {
+            return result["bottom-left-second"];
+        }
+        if (bottom >= 5 && bottom <= 15 && right >= 25 && right <= 35 && types.contains("bottom-right-second")) {
+            return result["bottom-right-second"];
+        }
+
+        //topcenter或bottomcenter
+        if (left >= halfW - 10 && left <= halfW + 10 && (topcenterCount > 0 || bottomcenterCount > 0)) {
+            for (var i = 1; i <= topcenterCount; i++) {
+                var s = (topcenterCount - i) * 20 + 5, e = s + 10;
+                if (top >= s && top <= e) {
+                    return result["top-center" + i];
+                }
+            }
+            for (var i = 1; i <= bottomcenterCount; i++) {
+                var s = (bottomcenterCount - i) * 20 + 5, e = s + 10;
+                if (bottom >= s && bottom <= e) {
+                    return result["bottom-center" + i];
+                }
+            }
+        }
+        //leftcenter或rightcenter
+        if (top >= halfH - 10 && top <= halfH + 10 && (leftcenterCount > 0 || rightcenterCount > 0)) {
+            for (var i = 1; i <= leftcenterCount; i++) {
+                var s = (leftcenterCount - i) * 20 + 5, e = s + 10;
+                if (left >= s && left <= e) {
+                    return result["left-center" + i];
+                }
+            }
+            for (var i = 1; i <= rightcenterCount; i++) {
+                var s = (rightcenterCount - i) * 20 + 5, e = s + 10;
+                if (right >= s && right <= e) {
+                    return result["right-center" + i];
+                }
+            }
+        }
+
+        //缝隙
+        if (top <= 8 && types.contains("top-gap")) {
+            return result["top-gap"];
+        }
+        if (bottom <= 8 && types.contains("bottom-gap")) {
+            return result["bottom-gap"];
+        }
+
+        //三分
+        if (top <= 15 && left >= 15 && right >= 15 && types.contains("top-line")) {
+            return result["top-line"];
+        }
+        if (left <= 15 && top >= 15 && bottom >= 15 && types.contains("left-line")) {
+            return result["left-line"];
+        }
+        if (right <= 15 && top >= 15 && bottom >= 15 && types.contains("right-line")) {
+            return result["right-line"];
+        }
+        if (bottom <= 15 && left >= 15 && right >= 15 && types.contains("bottom-line")) {
+            return result["bottom-line"];
+        }
+
+        //平分
+        if (top <= 1 / 4 * bound.height && types.contains("top")) {
+            return result["top"];
+        }
+        if (top >= 3 / 4 * bound.height && types.contains("bottom")) {
+            return result["bottom"];
+        }
+        if (left <= bound.width / 2 && types.contains("left")) {
+            return result["left"];
+        }
+        return result["right"];
+    },
+
+
+    _getScrollOffset: function () {
+        return {
+            left: this.scrollContainer.element[0].scrollLeft,
+            top: this.scrollContainer.element[0].scrollTop
+        }
+    },
+
+    ////操作////
+    _createOneRegion: function (item) {
+        var el = BI.createWidget(item.el);
+        el.setVisible(true);
+        return {
+            id: el.attr("id"),
+            left: item.left,
+            top: item.top,
+            width: item.width,
+            height: item.height,
+            el: el
+        }
+    },
+
+    _createOneDrop: function (region) {
+        if (this.storeDrops[region.id]) {
+            var drop = this.storeDrops[region.id].el;
+            drop.setVisible(true);
+        } else {
+            var drop = BI.createWidget({
+                type: "bi.layout",
+                cls: "arrangement-drop-region",
+                widgetName: region.id
+            });
+        }
+        return {
+            id: region.id,
+            left: region.left,
+            top: region.top,
+            width: region.width,
+            height: region.height,
+            el: drop
+        }
+    },
+
+    _calculateDrops: function () {
+        var self = this;
+        BI.each(this.drops, function (id, drop) {
+            drop.el.empty();
+            var devides = self._splitRegions(id);
+            var topcenterCount = 0, bottomcenterCount = 0, leftcenterCount = 0, rightcenterCount = 0;
+            var absolutes = [];
+            var horizontals = [];
+            var verticals = [];
+            BI.each(devides, function (i, devide) {
+                if (devide.type.indexOf("top-center") > -1) {
+                    topcenterCount++;
+                } else if (devide.type.indexOf("bottom-center") > -1) {
+                    bottomcenterCount++;
+                } else if (devide.type.indexOf("left-center") > -1) {
+                    leftcenterCount++;
+                } else if (devide.type.indexOf("right-center") > -1) {
+                    rightcenterCount++;
+                }
+            });
+            BI.each(devides, function (i, devide) {
+                switch (devide.type) {
+                    case "left-top":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 5,
+                            top: 5
+                        });
+                        break;
+                    case "top-right":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 5,
+                            top: 5
+                        });
+                        break;
+                    case "bottom-left":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 5,
+                            bottom: 5
+                        });
+                        break;
+                    case "bottom-right":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 5,
+                            bottom: 5
+                        });
+                        break;
+                    case "top-left":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 25,
+                            top: 5
+                        });
+                        break;
+                    case "top-right-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 25,
+                            top: 5
+                        });
+                        break;
+                    case "bottom-left-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            left: 25,
+                            bottom: 5
+                        });
+                        break;
+                    case "bottom-right-second":
+                        absolutes.push({
+                            el: {
+                                type: "bi.layout",
+                                width: 10,
+                                height: 10,
+                                cls: "drop-devider"
+                            },
+                            right: 25,
+                            bottom: 5
+                        });
+                        break;
+                    default:
+                        if (devide.type.indexOf("top-center") > -1) {
+                            var num = devide.type.split("top-center")[1];
+                            horizontals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 20,
+                                    height: 10,
+                                    cls: "drop-devider"
+                                },
+                                tgap: 20 * (topcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("bottom-center") > -1) {
+                            var num = devide.type.split("bottom-center")[1];
+                            horizontals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 20,
+                                    height: 10,
+                                    cls: "drop-devider"
+                                },
+                                bgap: 20 * (bottomcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("left-center") > -1) {
+                            var num = devide.type.split("left-center")[1];
+                            verticals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 10,
+                                    height: 20,
+                                    cls: "drop-devider"
+                                },
+                                lgap: 20 * (leftcenterCount - BI.parseInt(num)) + 5
+                            })
+                        } else if (devide.type.indexOf("right-center") > -1) {
+                            var num = devide.type.split("right-center")[1];
+                            verticals.push({
+                                el: {
+                                    type: "bi.layout",
+                                    width: 10,
+                                    height: 20,
+                                    cls: "drop-devider"
+                                },
+                                rgap: 20 * (rightcenterCount - BI.parseInt(num)) + 5
+                            })
+                        }
+                        break;
+                }
+
+            });
+            BI.createWidget({
+                type: "bi.absolute",
+                element: drop.el,
+                items: absolutes
+            });
+
+            BI.createWidget({
+                type: "bi.absolute_horizontal_adapt",
+                element: drop.el,
+                items: horizontals
+            });
+
+            BI.createWidget({
+                type: "bi.absolute_vertical_adapt",
+                element: drop.el,
+                items: verticals
+            });
+        });
+    },
+
+    _applyRegion: function (regions) {
+        var self = this, o = this.options;
+        BI.each(regions || this.regions, function (i, region) {
+            region.el.element.css({
+                left: region.left,
+                top: region.top,
+                width: region.width,
+                height: region.height
+            });
+            self.drops[region.id].left = region.left;
+            self.drops[region.id].top = region.top;
+            self.drops[region.id].width = region.width;
+            self.drops[region.id].height = region.height;
+        });
+        BI.each(this.drops, function (i, region) {
+            region.el.element.css({
+                left: region.left,
+                top: region.top,
+                width: region.width,
+                height: region.height
+            });
+        });
+        this._applyContainer();
+        this._calculateDrops();
+        this.ratio = this.getLayoutRatio();
+    },
+
+    _renderRegion: function () {
+        var self = this;
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: BI.toArray(this.regions)
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.droppable,
+            items: BI.toArray(this.drops)
+        });
+    },
+
+    getClientWidth: function () {
+        return this.scrollContainer.element[0].clientWidth;
+    },
+
+    getClientHeight: function () {
+        return this.scrollContainer.element[0].clientHeight;
+    },
+
+    _applyContainer: function () {
+        //先掩藏后显示能够明确滚动条是否出现
+        this.scrollContainer.element.css("overflow", "hidden");
+        var occupied = this._getRegionOccupied();
+        this.container.element.width(occupied.left + occupied.width).height(occupied.top + occupied.height);
+        this.scrollContainer.element.css("overflow", "auto");
+        return occupied;
+    },
+
+    _modifyRegion: function (regions) {
+        BI.each(this.regions, function (id, region) {
+            if (regions[id]) {
+                region.left = regions[id].left;
+                region.top = regions[id].top;
+                region.width = regions[id].width;
+                region.height = regions[id].height;
+            }
+        });
+        BI.each(this.drops, function (id, region) {
+            if (regions[id]) {
+                region.left = regions[id].left;
+                region.top = regions[id].top;
+                region.width = regions[id].width;
+                region.height = regions[id].height;
+            }
+        });
+    },
+
+    _addRegion: function (item) {
+        var region = this._createOneRegion(item);
+        this.regions[region.id] = region;
+        var drop = this._createOneDrop(region);
+        this.drops[drop.id] = drop;
+        this.storeDrops[drop.id] = drop;
+        this._locationRegion();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [region]
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.droppable,
+            items: [drop]
+        })
+    },
+
+    _deleteRegionByName: function (name) {
+        this.regions[name].el.setVisible(false);
+        this.drops[name].el.setVisible(false);
+        delete this.regions[name];
+        delete this.drops[name];
+        this._locationRegion();
+    },
+
+    _setArrangeSize: function (size) {
+        this.arrangement.element.css({
+            left: size.left,
+            top: size.top,
+            width: size.width,
+            height: size.height
+        })
+    },
+
+    //Grid
+    _getOneWidthPortion: function () {
+        return this.getClientWidth() / BI.Arrangement.PORTION;
+    },
+
+    _getGridPositionAndSize: function (position) {
+        var perWidth = this._getOneWidthPortion();
+        var widthPortion = Math.round(position.width / perWidth);
+        var leftPortion = Math.round(position.left / perWidth);
+        var topPortion = Math.round(position.top / BI.Arrangement.GRID_HEIGHT);
+        var heightPortion = Math.round(position.height / BI.Arrangement.GRID_HEIGHT);
+        // if (leftPortion > BI.Arrangement.PORTION) {
+        //     leftPortion = BI.Arrangement.PORTION;
+        // }
+        // if (widthPortion > BI.Arrangement.PORTION) {
+        //     widthPortion = BI.Arrangement.PORTION;
+        // }
+        // if (leftPortion + widthPortion > BI.Arrangement.PORTION) {
+        //     leftPortion = BI.Arrangement.PORTION - widthPortion;
+        // }
+        if (widthPortion === 0) {
+            widthPortion = 1;
+        }
+        if (heightPortion === 0) {
+            heightPortion = 1;
+        }
+        return {
+            x: leftPortion,
+            y: topPortion,
+            w: widthPortion,
+            h: heightPortion
+        }
+    },
+
+    _getBlockPositionAndSize: function (position) {
+        var perWidth = this._getOneWidthPortion();
+        return {
+            left: position.x * perWidth,
+            top: position.y * BI.Arrangement.GRID_HEIGHT,
+            width: position.w * perWidth,
+            height: position.h * BI.Arrangement.GRID_HEIGHT
+        };
+    },
+
+    _getLayoutsByRegions: function (regions) {
+        var self = this;
+        var result = [];
+        BI.each(regions || this.regions, function (id, region) {
+            result.push(BI.extend(self._getGridPositionAndSize(region), {
+                i: region.id
+            }))
+        });
+        return result;
+    },
+
+    _getLayoutIndexByName: function (layout, name) {
+        return BI.findIndex(layout, function (i, l) {
+            return l.i === name;
+        });
+    },
+
+    _setBlockPositionAndSize: function (size) {
+        this.block.element.css({
+            left: size.left,
+            top: size.top,
+            width: size.width,
+            height: size.height
+        });
+    },
+
+    _getRegionsByLayout: function (layout) {
+        var self = this;
+        var regions = {};
+        BI.each(layout, function (i, ly) {
+            regions[ly.i] = BI.extend(self._getBlockPositionAndSize(ly), {
+                id: ly.i
+            });
+        });
+        return regions;
+    },
+
+    _setRegionsByLayout: function (regions, layout) {
+        var self = this;
+        regions || (regions = this.regions);
+        BI.each(layout, function (i, ly) {
+            if (regions[ly.i]) {
+                BI.extend(regions[ly.i], self._getBlockPositionAndSize(ly));
+            }
+        });
+        return regions;
+    },
+
+    _moveElement: function (layout, l, x, y, isUserAction) {
+        var self = this;
+        if (l.static) return layout;
+
+        if (l.y === y && l.x === x) return layout;
+
+        var movingUp = y && l.y > y;
+        if (typeof x === 'number') l.x = x;
+        if (typeof y === 'number') l.y = y;
+        l.moved = true;
+
+        var sorted = this._sortLayoutItemsByRowCol(layout);
+        if (movingUp) sorted = sorted.reverse();
+        var collisions = getAllCollisions(sorted, l);
+
+        for (var i = 0, len = collisions.length; i < len; i++) {
+            var collision = collisions[i];
+            if (collision.moved) continue;
+
+            if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue;
+
+            if (collision.static) {
+                layout = this._moveElementAwayFromCollision(layout, collision, l, isUserAction);
+            } else {
+                layout = this._moveElementAwayFromCollision(layout, l, collision, isUserAction);
+            }
+        }
+
+        return layout;
+
+        function getAllCollisions(layout, layoutItem) {
+            return BI.filter(layout, function (i, l) {
+                return self._collides(l, layoutItem);
+            });
+        }
+    },
+
+    _sortLayoutItemsByRowCol: function (layout) {
+        return [].concat(layout).sort(function (a, b) {
+            if (a.y > b.y || (a.y === b.y && a.x > b.x)) {
+                return 1;
+            }
+            return -1;
+        });
+    },
+
+    _collides: function (l1, l2) {
+        if (l1 === l2) return false; // same element
+        if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2
+        if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2
+        if (l1.y + l1.h <= l2.y) return false; // l1 is above l2
+        if (l1.y >= l2.y + l2.h) return false; // l1 is below l2
+        return true; // boxes overlap
+    },
+
+    _getFirstCollision: function (layout, layoutItem) {
+        for (var i = 0, len = layout.length; i < len; i++) {
+            if (this._collides(layout[i], layoutItem)) return layout[i];
+        }
+    },
+
+    _moveElementAwayFromCollision: function (layout, collidesWith,
+                                             itemToMove, isUserAction) {
+        if (isUserAction) {
+            var fakeItem = {
+                x: itemToMove.x,
+                y: itemToMove.y,
+                w: itemToMove.w,
+                h: itemToMove.h,
+                i: '-1'
+            };
+            fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0);
+            if (!this._getFirstCollision(layout, fakeItem)) {
+                return this._moveElement(layout, itemToMove, undefined, fakeItem.y);
+            }
+        }
+
+        return this._moveElement(layout, itemToMove, undefined, itemToMove.y + 1);
+    },
+
+    _compactItem: function (compareWith, l, verticalCompact) {
+        if (verticalCompact) {
+            while (l.y > 0 && !this._getFirstCollision(compareWith, l)) {
+                l.y--;
+            }
+        }
+
+        var collides;
+        while ((collides = this._getFirstCollision(compareWith, l))) {
+            l.y = collides.y + collides.h;
+        }
+        return l;
+    },
+
+    compact: function (layout, verticalCompact) {
+        var compareWith = getStatics(layout);
+        var sorted = this._sortLayoutItemsByRowCol(layout);
+        var out = [];
+
+        for (var i = 0, len = sorted.length; i < len; i++) {
+            var l = sorted[i];
+
+            if (!l.static) {
+                l = this._compactItem(compareWith, l, verticalCompact);
+
+                compareWith.push(l);
+            }
+
+            out[layout.indexOf(l)] = l;
+
+            l.moved = false;
+        }
+
+        return out;
+        function getStatics(layout) {
+            return BI.filter(layout, function (i, l) {
+                return l.static;
+            });
+        }
+    },
+
+    ////公有方法////
+    getRegionByName: function (name) {
+        var obj = {};
+        obj[name] = this.regions[name];
+        return this._cloneRegion(obj)[name];
+    },
+
+    getAllRegions: function () {
+        return BI.toArray(this._cloneRegion());
+    },
+
+    getHelper: function () {
+        var helper = BI.createWidget({
+            type: "bi.layout",
+            width: 18,
+            height: 18,
+            cls: "arrangement-helper"
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [helper]
+        });
+        return helper;
+    },
+
+    _start: function (cur) {
+        this.arrangement.setVisible(true);
+        this.droppable.setVisible(true);
+        if (this.options.layoutType === BI.Arrangement.LAYOUT_TYPE.GRID) {
+            this.block.setVisible(true);
+        }
+        BI.each(this.drops, function (i, drop) {
+            drop.el.setVisible(false);
+        });
+        if (cur) {
+            if (this.drops[cur]) {
+                this.drops[cur].el.setVisible(true);
+            }
+        }
+    },
+
+    _stop: function () {
+        this.arrangement.setVisible(false);
+        this.droppable.setVisible(false);
+        this.block.setVisible(false);
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        direction || (direction = ["top", "bottom", "left", "right"]);
+        var self = this, result = {};
+        BI.each(direction, function (i, dir) {
+            result[dir] = self._getDirectRelativeRegions(name, [dir]);
+        });
+        return result;
+    },
+
+    ////公有操作////
+    setLayoutType: function (type) {
+        var self = this, o = this.options;
+        if (type !== o.layoutType) {
+            o.layoutType = type;
+            switch (o.layoutType) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    this.relayout();
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    this.relayout();
+                    break;
+            }
+        }
+    },
+
+    getLayoutType: function () {
+        return this.options.layoutType;
+    },
+
+    getLayoutRatio: function () {
+        var occupied = this._getRegionOccupied();
+        var width = this.getClientWidth(), height = this.getClientHeight();
+        return {
+            x: BI.parseFloat(BI.contentFormat((occupied.left + occupied.width) / width, "#.##;-#.##")),
+            y: BI.parseFloat(BI.contentFormat((occupied.top + occupied.height) / height, "#.##;-#.##"))
+        }
+    },
+
+    addRegion: function (region, position) {
+        if (position) {
+            this.setPosition(position, region);
+        }
+        var self = this, o = this.options;
+        if (!this.position) {
+            return false;
+        }
+        var test = this._cloneRegion();
+        BI.each(this.position.regions, function (i, region) {
+            test[region.id].left = region.left;
+            test[region.id].top = region.top;
+            test[region.id].width = region.width;
+            test[region.id].height = region.height;
+
+        });
+        var item = BI.extend({}, region, {
+            left: this.position.insert.left,
+            top: this.position.insert.top,
+            width: this.position.insert.width,
+            height: this.position.insert.height
+        });
+        var added = this._createOneRegion(item);
+        test[added.id] = added;
+        if (this._test(test)) {
+            delete test[added.id];
+            this._modifyRegion(test);
+            this._addRegion(item);
+            this._populate(this.getAllRegions());
+            return true;
+        }
+        return false;
+    },
+
+    deleteRegion: function (name) {
+        if (!this.regions[name]) {
+            return false;
+        }
+        var self = this, o = this.options;
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var clone = this._cloneRegion();
+                var regions = this._getEquivalentRelativeRegions(name);
+                if (regions.length > 0) {
+                    BI.each(regions, function (i, region) {
+                        BI.extend(clone[region.id], region);
+                    });
+                    this._modifyRegion(clone);
+                }
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                return true;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this._deleteRegionByName(name);
+                this._populate(this.getAllRegions());
+                this.resize();
+                return true;
+        }
+        return false;
+    },
+
+    setRegionSize: function (name, size) {
+        var self = this, o = this.options;
+        var flag = false;
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                var current = this.regions[name];
+                if (size.width !== current.width) {
+                    var regions = this._getInDirectRelativeRegions(name, ["right"]).right;
+                    var lefts = regions.left || [], rights = regions.right || [];
+                    var offset = size.width - current.width;
+                    var cloned = this._cloneRegion();
+                    BI.some(lefts, function (i, left) {
+                        var region = cloned[left.id];
+                        region.width = region.width + offset;
+                    });
+                    BI.some(rights, function (i, right) {
+                        var region = cloned[right.id];
+                        region.width = region.width - offset;
+                        region.left = region.left + offset;
+                    });
+                    if (this._test(cloned) && this._isArrangeFine(cloned)) {
+                        this._modifyRegion(cloned);
+                        flag = true;
+                    }
+                }
+                if (size.height !== current.height) {
+                    var regions = this._getInDirectRelativeRegions(name, ["bottom"]).bottom;
+                    var tops = regions.top || [], bottoms = regions.bottom || [];
+                    var offset = size.height - current.height;
+                    var cloned = this._cloneRegion();
+                    BI.some(tops, function (i, top) {
+                        var region = cloned[top.id];
+                        region.height = region.height + offset;
+                    });
+                    BI.some(bottoms, function (i, bottom) {
+                        var region = cloned[bottom.id];
+                        region.height = region.height - offset;
+                        region.top = region.top + offset;
+                    });
+                    if (this._test(cloned) && this._isArrangeFine(cloned)) {
+                        this._modifyRegion(cloned);
+                        flag = true;
+                    }
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var clone = this._cloneRegion();
+                BI.extend(clone[name], {
+                    width: size.width,
+                    height: size.height
+                });
+                if (this._test(clone)) {
+                    this._modifyRegion(clone);
+                    flag = true;
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var clone = this._cloneRegion();
+                BI.extend(clone[name], {
+                    width: size.width,
+                    height: size.height
+                });
+                if (this._test(clone)) {
+                    var layout = this._getLayoutsByRegions(clone);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    flag = true;
+                }
+                break;
+        }
+        this._locationRegion();
+        this._applyRegion();
+        return flag;
+    },
+
+    setPosition: function (position, size) {
+        var self = this, o = this.options;
+        var insert, regions = [], cur;
+        if (position.left < 0 || position.top < 0) {
+            switch (o.layoutType) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    this.resize();
+                    break;
+            }
+            this._stop();
+            this.position = null;
+            return null;
+        }
+        var offset = this._getScrollOffset();
+        position = {
+            left: position.left + offset.left,
+            top: position.top + offset.top
+        };
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (BI.isEmpty(this.regions)) {
+                    if (self._isPositionInBounds(position, {
+                            left: 0,
+                            top: 0,
+                            width: this.element[0].clientWidth,
+                            height: this.element[0].clientHeight
+                        })) {
+                        insert = {
+                            left: 0,
+                            top: 0,
+                            width: this.element[0].clientWidth,
+                            height: this.element[0].clientHeight
+                        };
+                    }
+                } else {
+                    if (BI.some(this.regions, function (id, region) {
+                            if (self._isPositionInBounds(position, region)) {
+                                var at = self._positionAt(position, region);
+                                if (!at) {
+                                    insert = null;
+                                } else {
+                                    insert = at.insert;
+                                    regions = at.regions;
+                                }
+                                cur = id;
+                                return true;
+                            }
+                        })) {
+                    }
+                    else {
+                        insert = null;
+                        regions = [];
+                    }
+                }
+                if (insert == null) {
+                    this._stop();
+                    self.position = null;
+                    break;
+                }
+
+                this.position = {
+                    insert: insert,
+                    regions: regions
+                };
+                this._setArrangeSize(insert);
+                this._start(cur);
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var insert = {
+                    top: position.top < 0 ? 0 : position.top,
+                    left: position.left < 0 ? 0 : position.left,
+                    width: size.width,
+                    height: size.height
+                };
+                this.position = {
+                    insert: insert
+                };
+                this._setArrangeSize(insert);
+                this._start();
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var p = {
+                    top: position.top < 0 ? 0 : position.top,
+                    left: position.left < 0 ? 0 : position.left,
+                    width: size.width,
+                    height: size.height
+                };
+                this._setArrangeSize(p);
+                var cur = this._getGridPositionAndSize(p);
+                var layout = [{
+                    x: 0, y: BI.MAX, w: cur.w, h: cur.h, i: cur.i
+                }].concat(this._getLayoutsByRegions());
+                layout = this._moveElement(layout, layout[0], cur.x, cur.y, true);
+                layout = this.compact(layout, true);
+                var regions = this._setRegionsByLayout(this._cloneRegion(), layout);
+                var insert = this._getBlockPositionAndSize(layout[0]);
+                this.position = {
+                    insert: insert,
+                    regions: regions
+                };
+                this._applyRegion(regions);
+                this._setBlockPositionAndSize(insert);
+                this._start();
+                break;
+        }
+        return this.position;
+    },
+
+    setRegionPosition: function (name, position) {
+        var self = this, o = this.options;
+        var offset = this._getScrollOffset();
+        position = BI.extend(position, {
+            left: position.left + offset.left,
+            top: position.top + offset.top
+        });
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                BI.extend(this.regions[name], {
+                    left: position.left < 0 ? 0 : position.left,
+                    top: position.top < 0 ? 0 : position.top
+                });
+                this._applyRegion();
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (!position.stop) {
+                    BI.extend(this.regions[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    });
+                    var cloned = this._cloneRegion();
+                    var cur = this._getGridPositionAndSize(BI.extend(cloned[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    }));
+                    var x = cur.x, y = cur.y;
+                    cur = BI.extend(cur, {
+                        x: 0, y: BI.MAX, i: -1
+                    });
+                    delete cloned[name];
+                    var layout = this._getLayoutsByRegions(cloned);
+                    layout = this._moveElement([cur].concat(layout), cur, x, y, true);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._applyRegion();
+
+                    this._setBlockPositionAndSize(this._getBlockPositionAndSize(cur));
+                    this.block.setVisible(true);
+                } else {
+                    BI.extend(this.regions[name], {
+                        left: position.left < 0 ? 0 : position.left,
+                        top: position.top < 0 ? 0 : position.top
+                    });
+                    var cloned = this._cloneRegion();
+                    var layout = this._getLayoutsByRegions(cloned);
+                    layout = this.compact(layout, true);
+                    var regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._applyRegion();
+                    this.block.setVisible(false);
+                }
+                break;
+        }
+    },
+
+    setContainerSize: function (size) {
+        var self = this, o = this.options;
+        var occupied = this._getRegionOccupied();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = size.width, height = size.height;
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.width = region.width / occupied.width * width;
+                        //region.height = region.height / occupied.height * height;
+                    });
+                    BI.each(regions, function (id, region) {
+                        var lefts = self.locations[id].left;
+                        var tops = self.locations[id].top;
+                        var bottoms = self.locations[id].bottom;
+                        var maxRegion;
+                        if (lefts.length > 0) {
+                            var ids = self._getRegionNames(lefts);
+                            var rs = self._getRegionsByNames(ids);
+                            maxRegion = self._getRegionOccupied(rs);
+                            region.left = maxRegion.left + maxRegion.width / occupied.width * width;
+                        } else {
+                            region.left = 0;
+                        }
+                        if (bottoms.length === 0) {
+                            region.height = height - region.top;
+                        }
+                        //if (tops.length > 0) {
+                        //    var ids = self._getRegionNames(tops);
+                        //    var rs = self._getRegionsByNames(ids);
+                        //    maxRegion = self._getRegionOccupied(rs);
+                        //    region.top = maxRegion.top + maxRegion.height / occupied.height * height;
+                        //}
+                        //if (tops.length === 0) {
+                        //    region.top = 0;
+                        //}
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+        this.resize();
+    },
+
+    scrollTo: function (top) {
+        this.scrollContainer.element.scrollTop(top);
+    },
+
+    zoom: function (ratio) {
+        var self = this, o = this.options;
+        if (!ratio) {
+            return;
+        }
+        var occupied = this._applyContainer();
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth();
+                    var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width);
+                    //var yRatio = ratio.y * height / (occupied.top + occupied.height);
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.left = region.left * xRatio;
+                        //region.top = region.top * yRatio;
+                        region.width = region.width * xRatio;
+                        //region.height = region.height * yRatio;
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                    this.resize();
+                    // } else {
+                    this.relayout();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth();
+                    var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width);
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.left = region.left * xRatio;
+                        region.width = region.width * xRatio;
+                    });
+                    if (this._test(regions)) {
+                        var layout = this._getLayoutsByRegions(regions);
+                        layout = this.compact(layout, true);
+                        regions = this._getRegionsByLayout(layout);
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                } else {
+                    this.relayout();
+                }
+                break;
+        }
+    },
+
+    resize: function () {
+        var self = this, o = this.options;
+        var occupied = this._applyContainer();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (this._isArrangeFine()) {
+                    var width = this.getClientWidth(), height = this.getClientHeight();
+                    var isHeightAdjust = height > occupied.top + occupied.height;
+                    var regions = this._cloneRegion();
+                    BI.each(regions, function (i, region) {
+                        region.width = region.width / occupied.width * width;
+                        //if (isHeightAdjust) {
+                        //    region.height = region.height / occupied.height * height;
+                        //}
+                    });
+                    BI.each(regions, function (id, region) {
+                        var lefts = self.locations[id].left;
+                        var tops = self.locations[id].top;
+                        var bottoms = self.locations[id].bottom;
+                        var maxRegion;
+                        if (lefts.length > 0) {
+                            var ids = self._getRegionNames(lefts);
+                            var rs = self._getRegionsByNames(ids);
+                            maxRegion = self._getRegionOccupied(rs);
+                            region.left = maxRegion.left + maxRegion.width / occupied.width * width;
+                        } else {
+                            region.left = 0;
+                        }
+                        if (tops.length === 0) {
+                            region.top = 0;
+                        }
+                        if (isHeightAdjust && bottoms.length === 0) {
+                            region.height = height - region.top;
+                        }
+                        //if (isHeightAdjust && tops.length > 0) {
+                        //    var ids = self._getRegionNames(tops);
+                        //    var rs = self._getRegionsByNames(ids);
+                        //    maxRegion = self._getRegionOccupied(rs);
+                        //    region.top = maxRegion.top + maxRegion.height / occupied.height * height;
+                        //}
+                    });
+                    if (this._test(regions)) {
+                        this._modifyRegion(regions);
+                        this._applyRegion();
+                    }
+                } else {
+                    this.relayout();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                this.zoom(this.ratio);
+                var regions = this._cloneRegion();
+                var layout = this._getLayoutsByRegions(regions);
+                layout = this.compact(layout, true);
+                regions = this._getRegionsByLayout(layout);
+                this._modifyRegion(regions);
+                this._applyRegion();
+                break;
+        }
+    },
+
+    relayout: function () {
+        var self = this, o = this.options;
+        if (o.isNeedReLayout === false) {
+            return;
+        }
+        //var occupied = this._applyContainer();
+        switch (o.layoutType) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                if (!this._isArrangeFine()) {
+                    var width = this.getClientWidth(), height = this.getClientHeight();
+                    var clone = BI.toArray(this._cloneRegion());
+                    clone.sort(function (r1, r2) {
+                        if (self._isEqual(r1.top, r2.top)) {
+                            return r1.left - r2.left;
+                        }
+                        return r1.top - r2.top;
+                    });
+                    var count = clone.length;
+                    var cols = 3, rows = Math.floor((count - 1) / 3 + 1);
+                    var w = width / cols, h = height / rows;
+                    var store = {};
+                    BI.each(clone, function (i, region) {
+                        var row = Math.floor(i / 3), col = i % 3;
+                        BI.extend(region, {
+                            top: row * 380,
+                            left: col * w,
+                            width: w,
+                            height: 380
+                        });
+                        if (!store[row]) {
+                            store[row] = {};
+                        }
+                        store[row][col] = region;
+                    });
+                    //非3的倍数
+                    if (count % 3 !== 0) {
+                        var lasts = store[rows - 1];
+                        var perWidth = width / (count % 3);
+                        BI.each(lasts, function (i, region) {
+                            BI.extend(region, {
+                                left: BI.parseInt(i) * perWidth,
+                                width: perWidth
+                            });
+                        });
+                    }
+                    if (this._test(clone)) {
+                        this._populate(clone);
+                        this.resize();
+                    }
+                } else {
+                    this.resize();
+                }
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                var width = this.getClientWidth(), height = this.getClientHeight();
+                var regions = this._cloneRegion();
+                var clone = BI.toArray(regions);
+                clone.sort(function (r1, r2) {
+                    if (self._isEqual(r1.top, r2.top)) {
+                        return r1.left - r2.left;
+                    }
+                    return r1.top - r2.top;
+                });
+                var count = clone.length;
+                var cols = 3, rows = Math.floor((count - 1) / 3 + 1);
+                var w = width / cols, h = height / rows;
+                var store = {};
+                BI.each(clone, function (i, region) {
+                    var row = Math.floor(i / 3), col = i % 3;
+                    BI.extend(region, {
+                        top: row * 380,
+                        left: col * w,
+                        width: w,
+                        height: 380
+                    });
+                    if (!store[row]) {
+                        store[row] = {};
+                    }
+                    store[row][col] = region;
+                });
+                //非3的倍数
+                if (count % 3 !== 0) {
+                    var lasts = store[rows - 1];
+                    var perWidth = width / (count % 3);
+                    BI.each(lasts, function (i, region) {
+                        BI.extend(region, {
+                            left: BI.parseInt(i) * perWidth,
+                            width: perWidth
+                        });
+                    });
+                }
+                if (this._test(clone)) {
+                    var layout = this._getLayoutsByRegions(regions);
+                    layout = this.compact(layout, true);
+                    regions = this._getRegionsByLayout(layout);
+                    this._modifyRegion(regions);
+                    this._populate(clone);
+                }
+                break;
+        }
+    },
+
+    _populate: function (items) {
+        this._stop();
+        this._calculateRegions(items);
+        this._locationRegion();
+        this._applyRegion();
+    },
+
+    populate: function (items) {
+        var self = this;
+        BI.each(this.regions, function (name, region) {
+            self.regions[name].el.setVisible(false);
+            self.drops[name].el.setVisible(false);
+            delete self.regions[name];
+            delete self.drops[name];
+        });
+        this._populate(items);
+        this._renderRegion();
+    }
+});
+BI.extend(BI.Arrangement, {
+    PORTION: 24,
+    GRID_HEIGHT: 50,
+    LAYOUT_TYPE: {
+        ADAPTIVE: BICst.DASHBOARD_LAYOUT_ADAPT,
+        FREE: BICst.DASHBOARD_LAYOUT_FREE,
+        GRID: BICst.DASHBOARD_LAYOUT_GRID
+    }
+});
+$.shortcut('bi.arrangement', BI.Arrangement);
\ No newline at end of file
diff --git a/src/widget/base/combo/editoriconcheckcombo/combo.editoriconcheck.js b/src/widget/base/combo/editoriconcheckcombo/combo.editoriconcheck.js
new file mode 100644
index 000000000..df0ffa924
--- /dev/null
+++ b/src/widget/base/combo/editoriconcheckcombo/combo.editoriconcheck.js
@@ -0,0 +1,80 @@
+/**
+ * Created by Young's on 2016/4/28.
+ */
+BI.EditorIconCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.EditorIconCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-check-editor-combo",
+            width: 100,
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            allowBlank: true,
+            watermark: "",
+            errorText: ""
+        })
+    },
+
+    _init: function () {
+        BI.EditorIconCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.editor_trigger",
+            items: o.items,
+            height: o.height,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.trigger.on(BI.EditorTrigger.EVENT_CHANGE, function () {
+            self.popup.setValue(this.getValue());
+            self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE);
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.editorIconCheckCombo.hideView();
+            self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editorIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.editorIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.EditorIconCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.editorIconCheckCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.trigger.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.editorIconCheckCombo.populate(items);
+    }
+});
+BI.EditorIconCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.editor_icon_check_combo", BI.EditorIconCheckCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/formulacombo/combo.formula.js b/src/widget/base/combo/formulacombo/combo.formula.js
new file mode 100644
index 000000000..f5c7c9e83
--- /dev/null
+++ b/src/widget/base/combo/formulacombo/combo.formula.js
@@ -0,0 +1,99 @@
+/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaCombo
+ * @extend BI.Widget
+ */
+BI.FormulaCombo = BI.inherit(BI.Widget, {
+
+    _constant: {
+        POPUP_HEIGHT: 450,
+        POPUP_WIDTH: 600,
+        POPUP_V_GAP: 10,
+        POPUP_H_GAP: 10,
+        ADJUST_LENGTH: 2,
+        HEIGHT_MAX: 10000,
+        MAX_HEIGHT: 500,
+        MAX_WIDTH: 600,
+        COMBO_TRIGGER_WIDTH: 300
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-combo",
+            height: 30,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FormulaCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.formula_ids = [];
+        this.input = BI.createWidget({
+            type: "bi.formula_combo_trigger",
+            height: o.height,
+            items: o.items
+        });
+        this.formulaPopup = BI.createWidget({
+            type: "bi.formula_combo_popup",
+            fieldItems: o.items
+        });
+
+        this.formulaInputCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: true,
+            isNeedAdjustWidth: false,
+            adjustLength: this._constant.CONDITION_TYPE_COMBO_ADJUST,
+            el: this.input,
+            popup: {
+                el: {
+                    type: "bi.absolute",
+                    height: this._constant.HEIGHT_MAX,
+                    width: this._constant.POPUP_WIDTH,
+                    items: [{
+                        el: this.formulaPopup,
+                        top: this._constant.POPUP_V_GAP,
+                        left: this._constant.POPUP_H_GAP,
+                        right: this._constant.POPUP_V_GAP,
+                        bottom: 0
+                    }]
+                },
+                stopPropagation: false,
+                maxHeight: this._constant.MAX_HEIGHT,
+                width: this._constant.MAX_WIDTH
+            }
+        });
+        this.formulaInputCombo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.formulaPopup.setValue(self.input.getValue());
+        });
+        this.formulaPopup.on(BI.FormulaComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.formulaPopup.getValue());
+            self.formulaInputCombo.hideView();
+            self.fireEvent(BI.FormulaCombo.EVENT_CHANGE);
+        });
+        this.formulaPopup.on(BI.FormulaComboPopup.EVENT_VALUE_CANCEL, function () {
+            self.formulaInputCombo.hideView();
+        });
+    },
+
+    setValue: function (v) {
+        if (this.formulaInputCombo.isViewVisible()) {
+            this.formulaInputCombo.hideView();
+        }
+        this.input.setValue(v);
+        this.input.setText(BI.Func.getFormulaStringFromFormulaValue(v));
+        this.formulaPopup.setValue(this.input.getValue());
+    },
+
+    getFormulaTargetIds: function() {
+        return this.formulaPopup.getFormulaTargetIds();
+    },
+
+    getValue: function () {
+        return this.input.getValue();
+    }
+});
+BI.FormulaCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_combo", BI.FormulaCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/formulacombo/popup.formulacombo.js b/src/widget/base/combo/formulacombo/popup.formulacombo.js
new file mode 100644
index 000000000..0d3f96d13
--- /dev/null
+++ b/src/widget/base/combo/formulacombo/popup.formulacombo.js
@@ -0,0 +1,89 @@
+/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaComboPopup
+ * @extend BI.Widget
+ */
+BI.FormulaComboPopup = BI.inherit(BI.Widget, {
+
+    _constant: {
+        BUTTON_HEIGHT: 30,
+        SOUTH_HEIGHT: 60,
+        SOUTH_H_GAP: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-pane-popup"
+        })
+    },
+
+    _init: function () {
+        BI.FormulaComboPopup.superclass._init.apply(this, arguments);
+        this.populate();
+    },
+
+    populate: function () {
+        var self = this, fieldItems = this.options.fieldItems;
+        this.formula = BI.createWidget({
+            type: "bi.formula_insert"
+        });
+        this.formula.populate(fieldItems);
+        var confirmButton = BI.createWidget({
+            type: "bi.button",
+            level: "common",
+            height: this._constant.BUTTON_HEIGHT,
+            text: BI.i18nText("BI-Basic_OK")
+        });
+        var cancelButton = BI.createWidget({
+            type: "bi.button",
+            level: "ignore",
+            height: this._constant.BUTTON_HEIGHT,
+            text: BI.i18nText("BI-Basic_Cancel")
+        });
+
+        this.formula.on(BI.FormulaInsert.EVENT_CHANGE, function () {
+            confirmButton.setEnable(self.formula.checkValidation());
+        });
+        confirmButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FormulaComboPopup.EVENT_CHANGE);
+        });
+        cancelButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.setValue(self.oldValue);
+            self.fireEvent(BI.FormulaComboPopup.EVENT_VALUE_CANCEL);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.formula,
+                height: "fill"
+            }, {
+                el: {
+                    type: "bi.right_vertical_adapt",
+                    height: this._constant.SOUTH_HEIGHT,
+                    items: [cancelButton, confirmButton],
+                    hgap: this._constant.SOUTH_H_GAP
+                },
+                height: this._constant.SOUTH_HEIGHT
+            }]
+        })
+    },
+
+    getFormulaTargetIds: function(){
+        return this.formula.getUsedFields();
+    },
+
+    getValue: function () {
+        return this.formula.getValue();
+    },
+
+    setValue: function (v) {
+        this.oldValue = v;
+        this.formula.setValue(v);
+    }
+});
+BI.FormulaComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FormulaComboPopup.EVENT_VALUE_CANCEL = "EVENT_VALUE_CANCEL";
+$.shortcut("bi.formula_combo_popup", BI.FormulaComboPopup);
\ No newline at end of file
diff --git a/src/widget/base/combo/formulacombo/trigger.formulacombo.js b/src/widget/base/combo/formulacombo/trigger.formulacombo.js
new file mode 100644
index 000000000..85f6a005b
--- /dev/null
+++ b/src/widget/base/combo/formulacombo/trigger.formulacombo.js
@@ -0,0 +1,59 @@
+/**
+ * Created by GUY on 2016/4/25.
+ *
+ * @class BI.FormulaComboTrigger
+ * @extend BI.Widget
+ */
+BI.FormulaComboTrigger = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaComboTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-combo-trigger",
+            height: 30,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FormulaComboTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.label = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            textHeight: this.options.height,
+            lgap: 10
+        });
+    },
+
+    _getTextFromFormulaValue: function (formulaValue) {
+        var self = this;
+        var formulaString = "";
+        var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)/g;
+        var result = formulaValue.match(regx);
+        BI.each(result, function (i, item) {
+            var fieldRegx = /\$[\{][^\}]*[\}]/;
+            var str = item.match(fieldRegx);
+            if (BI.isNotEmptyArray(str)) {
+                var id = str[0].substring(2, item.length - 1);
+                var item = BI.find(self.options.items, function (i, item) {
+                    return id === item.value;
+                });
+                formulaString = formulaString + item.text;
+            } else {
+                formulaString = formulaString + item;
+            }
+        });
+        return formulaString;
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    setValue: function (v) {
+        this.options.value = v;
+        this.label.setText(this._getTextFromFormulaValue(v));
+    }
+});
+$.shortcut("bi.formula_combo_trigger", BI.FormulaComboTrigger);
\ No newline at end of file
diff --git a/src/widget/base/combo/iconcombo/combo.icon.js b/src/widget/base/combo/iconcombo/combo.icon.js
new file mode 100644
index 000000000..157ae9527
--- /dev/null
+++ b/src/widget/base/combo/iconcombo/combo.icon.js
@@ -0,0 +1,99 @@
+/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconCombo
+ * @extend BI.Widget
+ */
+BI.IconCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-icon-combo",
+            width: 24,
+            height: 24,
+            iconClass: "",
+            el: {},
+            popup: {},
+            minWidth: 100,
+            maxWidth: 'auto',
+            maxHeight: 300,
+            direction: "bottom",
+            adjustLength: 3,//调整的距离
+            adjustXOffset: 0,
+            adjustYOffset: 0,
+            offsetStyle: "left",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        })
+    },
+
+    _init: function () {
+        BI.IconCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.icon_combo_trigger",
+            iconClass: o.iconClass,
+            title: o.title,
+            items: o.items,
+            width: o.width,
+            height: o.height,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight
+        });
+        this.popup = BI.createWidget(o.popup, {
+            type: "bi.icon_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.IconComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.iconCombo.hideView();
+            self.fireEvent(BI.IconCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.iconCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            direction: o.direction,
+            adjustLength: o.adjustLength,
+            adjustXOffset: o.adjustXOffset,
+            adjustYOffset: o.adjustYOffset,
+            offsetStyle: o.offsetStyle,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxWidth: o.maxWidth,
+                maxHeight: o.maxHeight,
+                minWidth: o.minWidth
+            }
+        });
+    },
+
+    showView: function () {
+        this.iconCombo.showView();
+    },
+
+    hideView: function () {
+        this.iconCombo.hideView();
+    },
+
+    setValue: function (v) {
+        this.iconCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.IconCombo.superclass.setEnable.apply(this, arguments);
+        this.iconCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.iconCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.iconCombo.populate(items);
+    }
+});
+BI.IconCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo", BI.IconCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/iconcombo/popup.iconcombo.js b/src/widget/base/combo/iconcombo/popup.iconcombo.js
new file mode 100644
index 000000000..04abb1afb
--- /dev/null
+++ b/src/widget/base/combo/iconcombo/popup.iconcombo.js
@@ -0,0 +1,63 @@
+/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconComboPopup
+ * @extend BI.Pane
+ */
+BI.IconComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi.icon-combo-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.IconComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.single_select_icon_text_item",
+                height: 30
+            }),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.IconComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    populate: function (items) {
+        BI.IconComboPopup.superclass.populate.apply(this, arguments);
+        items = BI.createItems(items, {
+            type: "bi.single_select_icon_text_item",
+            height: 30
+        });
+        this.popup.populate(items);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.IconComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo_popup", BI.IconComboPopup);
\ No newline at end of file
diff --git a/src/widget/base/combo/iconcombo/trigger.iconcombo.js b/src/widget/base/combo/iconcombo/trigger.iconcombo.js
new file mode 100644
index 000000000..c6c7e2d0f
--- /dev/null
+++ b/src/widget/base/combo/iconcombo/trigger.iconcombo.js
@@ -0,0 +1,90 @@
+/**
+ * Created by GUY on 2016/2/2.
+ *
+ * @class BI.IconComboTrigger
+ * @extend BI.Widget
+ */
+BI.IconComboTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        return BI.extend(BI.IconComboTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-icon-combo-trigger",
+            el: {},
+            items: [],
+            iconClass: "",
+            width: 25,
+            height: 25,
+            isShowDown: true
+        });
+    },
+
+    _init: function () {
+        BI.IconComboTrigger.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.button = BI.createWidget(o.el, {
+            type: "bi.icon_change_button",
+            cls: "icon-combo-trigger-icon " + o.iconClass,
+            disableSelected: true,
+            width: o.width,
+            height: o.height,
+            iconWidth: o.iconWidth,
+            iconHeight: o.iconHeight
+        });
+        this.down = BI.createWidget({
+            type: "bi.icon_button",
+            disableSelected: true,
+            cls: "icon-combo-down-icon trigger-triangle-font",
+            width: 12,
+            height: 8
+        });
+        this.down.setVisible(o.isShowDown);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.button,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.down,
+                right: 0,
+                bottom: 0
+            }]
+        });
+        if (BI.isKey(o.value)) {
+            this.setValue(o.value);
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options;
+        this.options.items = items || [];
+        this.button.setIcon(o.iconClass);
+        this.button.setSelected(false);
+        this.down.setSelected(false);
+    },
+
+    setValue: function (v) {
+        BI.IconComboTrigger.superclass.setValue.apply(this, arguments);
+        var o = this.options;
+        var iconClass = "";
+        v = BI.isArray(v) ? v[0] : v;
+        if (BI.any(this.options.items, function (i, item) {
+                if (v === item.value) {
+                    iconClass = item.iconClass;
+                    return true;
+                }
+            })) {
+            this.button.setIcon(iconClass);
+            this.button.setSelected(true);
+            this.down.setSelected(true);
+        } else {
+            this.button.setIcon(o.iconClass);
+            this.button.setSelected(false);
+            this.down.setSelected(false);
+        }
+    }
+});
+BI.IconComboTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.icon_combo_trigger", BI.IconComboTrigger);
\ No newline at end of file
diff --git a/src/widget/base/combo/staticcombo/combo.static.js b/src/widget/base/combo/staticcombo/combo.static.js
new file mode 100644
index 000000000..f3c954a38
--- /dev/null
+++ b/src/widget/base/combo/staticcombo/combo.static.js
@@ -0,0 +1,67 @@
+/**
+ * 单选combo
+ *
+ * @class BI.StaticCombo
+ * @extend BI.Widget
+ */
+BI.StaticCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.StaticCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-static-combo",
+            height: 30,
+            text: "",
+            el: {},
+            items: [],
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        })
+    },
+
+    _init: function () {
+        BI.StaticCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.text_icon_item",
+            cls: "bi-select-text-trigger pull-down-font",
+            text: o.text,
+            readonly: true,
+            textLgap: 5,
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            textAlign: o.textAlign,
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.combo.hideView();
+            self.fireEvent(BI.StaticCombo.EVENT_CHANGE, arguments);
+        });
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+
+    getValue: function () {
+        return this.combo.getValue();
+    }
+});
+BI.StaticCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.static_combo", BI.StaticCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecheckcombo/combo.textvaluecheck.js b/src/widget/base/combo/textvaluecheckcombo/combo.textvaluecheck.js
new file mode 100644
index 000000000..21e8648a6
--- /dev/null
+++ b/src/widget/base/combo/textvaluecheckcombo/combo.textvaluecheck.js
@@ -0,0 +1,78 @@
+/**
+ * @class BI.TextValueCheckCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : check + text
+ */
+BI.TextValueCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-text-value-check-combo",
+            width: 100,
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextValueCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.textIconCheckCombo.hideView();
+            self.fireEvent(BI.TextValueCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.textIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setTitle: function (title) {
+        this.trigger.setTitle(title);
+    },
+
+    setValue: function (v) {
+        this.textIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.textIconCheckCombo.setEnable(v);
+    },
+
+    setWarningTitle: function (title) {
+        this.trigger.setWarningTitle(title);
+    },
+
+    getValue: function () {
+        return this.textIconCheckCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.textIconCheckCombo.populate(items);
+    }
+});
+BI.TextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_check_combo", BI.TextValueCheckCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecheckcombo/combo.textvaluechecksmall.js b/src/widget/base/combo/textvaluecheckcombo/combo.textvaluechecksmall.js
new file mode 100644
index 000000000..9a411e807
--- /dev/null
+++ b/src/widget/base/combo/textvaluecheckcombo/combo.textvaluechecksmall.js
@@ -0,0 +1,69 @@
+/**
+ * @class BI.SmallTextValueCheckCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : check + text
+ */
+BI.SmallTextValueCheckCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SmallTextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), {
+            width: 100,
+            height: 24,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.SmallTextValueCheckCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.small_select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_check_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.SmallTextIconCheckCombo.hideView();
+            self.fireEvent(BI.SmallTextValueCheckCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.SmallTextIconCheckCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.SmallTextIconCheckCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.SmallTextValueCheckCombo.superclass.setEnable.apply(this, arguments);
+        this.SmallTextIconCheckCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.SmallTextIconCheckCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.SmallTextIconCheckCombo.populate(items);
+    }
+});
+BI.SmallTextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.small_text_value_check_combo", BI.SmallTextValueCheckCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecheckcombo/popup.textvaluecheck.js b/src/widget/base/combo/textvaluecheckcombo/popup.textvaluecheck.js
new file mode 100644
index 000000000..b5a0c9fcc
--- /dev/null
+++ b/src/widget/base/combo/textvaluecheckcombo/popup.textvaluecheck.js
@@ -0,0 +1,60 @@
+BI.TextValueCheckComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCheckComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-icon-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.TextValueCheckComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: this._formatItems(o.items),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.TextValueCheckComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    _formatItems: function (items) {
+        return BI.map(items, function (i, item) {
+            return BI.extend({
+                type: "bi.icon_text_item",
+                cls: "item-check-font bi-list-item",
+                height: 30
+            }, item);
+        });
+    },
+
+    populate: function (items) {
+        BI.TextValueCheckComboPopup.superclass.populate.apply(this, arguments);
+        this.popup.populate(this._formatItems(items));
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.TextValueCheckComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_check_combo_popup", BI.TextValueCheckComboPopup);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecombo/combo.textvalue.js b/src/widget/base/combo/textvaluecombo/combo.textvalue.js
new file mode 100644
index 000000000..b390cf09a
--- /dev/null
+++ b/src/widget/base/combo/textvaluecombo/combo.textvalue.js
@@ -0,0 +1,71 @@
+/**
+ * @class BI.TextValueCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.TextValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseClass: "bi-text-value-combo",
+            height: 30,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            text: "",
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.TextValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.textIconCombo.hideView();
+            self.fireEvent(BI.TextValueCombo.EVENT_CHANGE, arguments);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.textIconCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.textIconCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueCombo.superclass.setEnable.apply(this, arguments);
+        this.textIconCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.textIconCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.textIconCombo.populate(items);
+    }
+});
+BI.TextValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_combo", BI.TextValueCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecombo/combo.textvaluesmall.js b/src/widget/base/combo/textvaluecombo/combo.textvaluesmall.js
new file mode 100644
index 000000000..2b5317621
--- /dev/null
+++ b/src/widget/base/combo/textvaluecombo/combo.textvaluesmall.js
@@ -0,0 +1,71 @@
+/**
+ * @class BI.SmallTextValueCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.SmallTextValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SmallTextValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            width: 100,
+            height: 24,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            el: {},
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.SmallTextValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el, {
+            type: "bi.small_select_text_trigger",
+            items: o.items,
+            height: o.height,
+            text: o.text
+        });
+        this.popup = BI.createWidget({
+            type: "bi.text_value_combo_popup",
+            chooseType: o.chooseType,
+            items: o.items
+        });
+        this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.SmallTextValueCombo.hideView();
+            self.fireEvent(BI.SmallTextValueCombo.EVENT_CHANGE);
+        });
+        this.popup.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.SmallTextValueCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup,
+                maxHeight: 300
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.SmallTextValueCombo.setValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.SmallTextValueCombo.superclass.setEnable.apply(this, arguments);
+        this.SmallTextValueCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.SmallTextValueCombo.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.SmallTextValueCombo.populate(items);
+    }
+});
+BI.SmallTextValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.small_text_value_combo", BI.SmallTextValueCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluecombo/popup.textvalue.js b/src/widget/base/combo/textvaluecombo/popup.textvalue.js
new file mode 100644
index 000000000..4d4512b54
--- /dev/null
+++ b/src/widget/base/combo/textvaluecombo/popup.textvalue.js
@@ -0,0 +1,58 @@
+BI.TextValueComboPopup = BI.inherit(BI.Pane, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueComboPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-icon-popup",
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.TextValueComboPopup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.popup = BI.createWidget({
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.single_select_item",
+                textAlign: o.textAlign,
+                height: 30
+            }),
+            chooseType: o.chooseType,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.TextValueComboPopup.EVENT_CHANGE, val, obj);
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+    },
+
+    populate: function (items) {
+        BI.TextValueComboPopup.superclass.populate.apply(this, arguments);
+        items = BI.createItems(items, {
+            type: "bi.single_select_item",
+            height: 30
+        });
+        this.popup.populate(items);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        this.popup.setValue(v);
+    }
+
+});
+BI.TextValueComboPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_combo_popup", BI.TextValueComboPopup);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluedownlistcombo/combo.textvaluedownlist.js b/src/widget/base/combo/textvaluedownlistcombo/combo.textvaluedownlist.js
new file mode 100644
index 000000000..b44843f38
--- /dev/null
+++ b/src/widget/base/combo/textvaluedownlistcombo/combo.textvaluedownlist.js
@@ -0,0 +1,84 @@
+/**
+ * @class BI.TextValueDownListCombo
+ * @extend BI.Widget
+ */
+BI.TextValueDownListCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextValueDownListCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-value-down-list-combo",
+            height: 30,
+            text: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextValueDownListCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this._createValueMap();
+
+        this.trigger = BI.createWidget({
+            type: "bi.down_list_select_text_trigger",
+            height: o.height,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.down_list_combo",
+            element: this,
+            chooseType: BI.Selection.Single,
+            adjustLength: 2,
+            height: o.height,
+            el: this.trigger,
+            items: BI.deepClone(o.items)
+        });
+
+        this.combo.on(BI.DownListCombo.EVENT_CHANGE, function () {
+            self.setValue(self.combo.getValue()[0].value);
+            self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE);
+        });
+
+        this.combo.on(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, function () {
+            self.setValue(self.combo.getValue()[0].childValue);
+            self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE);
+        });
+    },
+
+    _createValueMap: function () {
+        var self = this;
+        this.valueMap = {};
+        BI.each(BI.flatten(this.options.items), function (idx, item) {
+            if (BI.has(item, "el")) {
+                BI.each(item.children, function (id, it) {
+                    self.valueMap[it.value] = {value: item.el.value, childValue: it.value}
+                });
+            } else {
+                self.valueMap[item.value] = {value: item.value};
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = this.valueMap[v];
+        this.combo.setValue([v]);
+        this.trigger.setValue(v.childValue || v.value);
+    },
+
+    setEnable: function (v) {
+        BI.TextValueDownListCombo.superclass.setEnable.apply(this, arguments);
+        this.combo.setEnable(v);
+    },
+
+    getValue: function () {
+        var v = this.combo.getValue()[0];
+        return [v.childValue || v.value];
+    },
+
+    populate: function (items) {
+        this.options.items = BI.flatten(items);
+        this.combo.populate(items);
+        this._createValueMap();
+    }
+});
+BI.TextValueDownListCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.text_value_down_list_combo", BI.TextValueDownListCombo);
\ No newline at end of file
diff --git a/src/widget/base/combo/textvaluedownlistcombo/trigger.textvaluedownlist.js b/src/widget/base/combo/textvaluedownlistcombo/trigger.textvaluedownlist.js
new file mode 100644
index 000000000..d221491f9
--- /dev/null
+++ b/src/widget/base/combo/textvaluedownlistcombo/trigger.textvaluedownlist.js
@@ -0,0 +1,54 @@
+/**
+ * 选择字段trigger, downlist专用
+ * 显示形式为 父亲值(儿子值)
+ *
+ * @class BI.DownListSelectTextTrigger
+ * @extends BI.Trigger
+ */
+BI.DownListSelectTextTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListSelectTextTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-select-text-trigger",
+            height: 24,
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.DownListSelectTextTrigger.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            element: this,
+            height: o.height,
+            items: this._formatItemArray(o.items),
+            text: o.text
+        });
+    },
+
+    _formatItemArray: function(){
+        var sourceArray = BI.flatten(BI.deepClone(this.options.items));
+        var targetArray = [];
+        BI.each(sourceArray, function(idx, item){
+            if(BI.has(item, "el")){
+                BI.each(item.children, function(id, it){
+                    it.text = item.el.text + "(" + it.text + ")";
+                });
+                targetArray = BI.concat(targetArray, item.children);
+            }else{
+                targetArray.push(item);
+            }
+        });
+        return targetArray;
+    },
+
+    setValue: function (vals) {
+        this.trigger.setValue(vals);
+    },
+
+    populate: function (items) {
+        this.trigger.populate(this._formatItemArray(items));
+    }
+});
+$.shortcut("bi.down_list_select_text_trigger", BI.DownListSelectTextTrigger);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.adapt.js b/src/widget/base/editor/editor.adapt.js
new file mode 100644
index 000000000..657a98c65
--- /dev/null
+++ b/src/widget/base/editor/editor.adapt.js
@@ -0,0 +1,162 @@
+/**
+ * 根据内容自适应长度的输入框
+ * @class BI.AdaptiveEditor
+ * @extends BI.Single
+ */
+BI.AdaptiveEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.AdaptiveEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-adapt-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.AdaptiveEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            element: this,
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_BLUR, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CLICK, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self._checkEditorLength();
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ENTER, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.SignEditor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.SignEditor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.AdaptiveEditor.EVENT_EMPTY);
+        });
+        this._checkEditorLength();
+    },
+
+    _checkEditorLength: function () {
+        var o = this.options;
+        this.element.width(BI.DOM.getTextSizeWidth(this.getValue(), 14) + 2 * o.hgap + o.lgap + o.rgap);
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (k) {
+        this.editor.setValue(k);
+        this._checkEditorLength();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.editor.getState();
+    },
+
+    setState: function (v) {
+
+    }
+});
+BI.AdaptiveEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.AdaptiveEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.AdaptiveEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.AdaptiveEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.AdaptiveEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.AdaptiveEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.AdaptiveEditor.EVENT_START = "EVENT_START";
+BI.AdaptiveEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.AdaptiveEditor.EVENT_STOP = "EVENT_STOP";
+BI.AdaptiveEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.AdaptiveEditor.EVENT_VALID = "EVENT_VALID";
+BI.AdaptiveEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.AdaptiveEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.AdaptiveEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.AdaptiveEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.AdaptiveEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.adapt_editor", BI.AdaptiveEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.clear.js b/src/widget/base/editor/editor.clear.js
new file mode 100644
index 000000000..e23b40e27
--- /dev/null
+++ b/src/widget/base/editor/editor.clear.js
@@ -0,0 +1,169 @@
+/**
+ * 有清楚按钮的文本框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallTextEditor
+ * @extends BI.SearchEditor
+ */
+BI.ClearEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.ClearEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-clear-editor",
+            height: 30,
+            errorText: "",
+            watermark: "",
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn
+        });
+    },
+    _init: function () {
+        BI.ClearEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            watermark: o.watermark,
+            allowBlank: true,
+            errorText: o.errorText,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker
+        });
+        this.clear = BI.createWidget({
+            type: "bi.icon_button",
+            stopEvent: true,
+            cls: "search-close-h-font"
+        });
+        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.setValue("");
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
+            self.fireEvent(BI.ClearEditor.EVENT_CLEAR);
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    el: this.editor
+                },
+                {
+                    el: this.clear,
+                    width: 25
+                }]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self._checkClear();
+            self.fireEvent(BI.ClearEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.ClearEditor.EVENT_KEY_DOWN, v);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_SPACE)
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_BACKSPACE)
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_VALID)
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_ERROR)
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_RESTRICT)
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self._checkClear();
+            self.fireEvent(BI.ClearEditor.EVENT_EMPTY)
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_REMOVE)
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_CONFIRM)
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.ClearEditor.EVENT_STOP);
+        });
+
+        this.clear.invisible();
+    },
+
+    _checkClear: function () {
+        if (!this.getValue()) {
+            this.clear.invisible();
+        } else {
+            this.clear.visible();
+        }
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    getValue: function () {
+        if (this.isValid()) {
+            var res = this.editor.getValue().match(/[\S]+/g);
+            return BI.isNull(res) ? "" : res[res.length - 1];
+        }
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+        if (BI.isKey(v)) {
+            this.clear.visible();
+        }
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    }
+});
+BI.ClearEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.ClearEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.ClearEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.ClearEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.ClearEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.ClearEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.ClearEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+BI.ClearEditor.EVENT_CLEAR = "EVENT_CLEAR";
+
+BI.ClearEditor.EVENT_START = "EVENT_START";
+BI.ClearEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.ClearEditor.EVENT_STOP = "EVENT_STOP";
+BI.ClearEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.ClearEditor.EVENT_VALID = "EVENT_VALID";
+BI.ClearEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.ClearEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.ClearEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.ClearEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.ClearEditor.EVENT_EMPTY = "EVENT_EMPTY";
+$.shortcut("bi.clear_editor", BI.ClearEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.search.js b/src/widget/base/editor/editor.search.js
new file mode 100644
index 000000000..83281a6ae
--- /dev/null
+++ b/src/widget/base/editor/editor.search.js
@@ -0,0 +1,198 @@
+/**
+ * Created by roy on 15/9/14.
+ */
+BI.SearchEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.SearchEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-search-editor",
+            height: 30,
+            errorText: "",
+            watermark: BI.i18nText("BI-Basic_Search"),
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn
+        });
+    },
+    _init: function () {
+        this.options.height -= 2;
+        BI.SearchEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            watermark: o.watermark,
+            allowBlank: true,
+            errorText: o.errorText,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker
+        });
+        this.clear = BI.createWidget({
+            type: "bi.icon_button",
+            stopEvent: true,
+            cls: "search-close-h-font"
+        });
+        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.setValue("");
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
+            self.fireEvent(BI.SearchEditor.EVENT_CLEAR);
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    el: {
+                        type: "bi.center_adapt",
+                        cls: "search-font",
+                        items: [{
+                            el: {
+                                type: "bi.icon"
+                            }
+                        }]
+                    },
+                    width: 25
+                },
+                {
+                    el: self.editor
+                },
+                {
+                    el: this.clear,
+                    width: 25
+                }
+            ]
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self._checkClear();
+            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SearchEditor.EVENT_KEY_DOWN, v);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_SPACE)
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_BACKSPACE)
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_VALID)
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_ERROR)
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_RESTRICT)
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self._checkClear();
+            self.fireEvent(BI.SearchEditor.EVENT_EMPTY)
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_REMOVE)
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_CONFIRM)
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SearchEditor.EVENT_STOP);
+        });
+
+        this.clear.invisible();
+    },
+
+    _checkClear: function () {
+        if (!this.getValue()) {
+            this.clear.invisible();
+        } else {
+            this.clear.visible();
+        }
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    getValue: function () {
+        if (this.isValid()) {
+            var res = this.editor.getValue().match(/[\S]+/g);
+            return BI.isNull(res) ? "" : res[res.length - 1];
+        }
+    },
+
+    getLastValidValue: function () {
+        return this.editor.getLastValidValue();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+        if (BI.isKey(v)) {
+            this.clear.visible();
+        }
+    },
+
+    setValid: function (b) {
+        this.editor.setValid(b);
+    },
+
+    isEditing: function () {
+        return this.editor.isEditing();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setEnable: function (b) {
+        BI.Editor.superclass.setEnable.apply(this, arguments);
+        this.editor && this.editor.setEnable(b);
+        this.clear.setEnabled(b);
+    }
+});
+BI.SearchEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SearchEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SearchEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SearchEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SearchEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SearchEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SearchEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+BI.SearchEditor.EVENT_CLEAR = "EVENT_CLEAR";
+
+BI.SearchEditor.EVENT_START = "EVENT_START";
+BI.SearchEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SearchEditor.EVENT_STOP = "EVENT_STOP";
+BI.SearchEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SearchEditor.EVENT_VALID = "EVENT_VALID";
+BI.SearchEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SearchEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SearchEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SearchEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.SearchEditor.EVENT_EMPTY = "EVENT_EMPTY";
+$.shortcut("bi.search_editor", BI.SearchEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.search.small.js b/src/widget/base/editor/editor.search.small.js
new file mode 100644
index 000000000..0d35346c8
--- /dev/null
+++ b/src/widget/base/editor/editor.search.small.js
@@ -0,0 +1,20 @@
+/**
+ * 小号搜索框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallSearchEditor
+ * @extends BI.SearchEditor
+ */
+BI.SmallSearchEditor = BI.inherit(BI.SearchEditor, {
+    _defaultConfig: function () {
+        var conf = BI.SmallSearchEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-small-search-editor",
+            height: 24
+        });
+    },
+
+    _init: function () {
+        BI.SmallSearchEditor.superclass._init.apply(this, arguments);
+    }
+});
+$.shortcut("bi.small_search_editor", BI.SmallSearchEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.sign.initial.js b/src/widget/base/editor/editor.sign.initial.js
new file mode 100644
index 000000000..b8bbf6b12
--- /dev/null
+++ b/src/widget/base/editor/editor.sign.initial.js
@@ -0,0 +1,165 @@
+/**
+ * sign是新值(初始value值)形式的自适应宽度的输入框
+ * @class BI.SignInitialEditor
+ * @extends BI.Single
+ */
+BI.SignInitialEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.SignInitialEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-sign-initial-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: true,
+            watermark: "",
+            errorText: "",
+            value: "",
+            text: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SignInitialEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            element: this,
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value || o.text,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        if(BI.isNotNull(o.value)){
+            this.setState(o.value);
+        }
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SignInitialEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            self.setState(self.editor.getValue());
+            self.fireEvent(BI.SignInitialEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.SignEditor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.SignEditor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SignInitialEditor.EVENT_EMPTY);
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v.value);
+        this.setState(v.value);
+    },
+
+    getValue: function () {
+        return {
+            value: this.editor.getValue(),
+            text: this.options.text
+        }
+    },
+
+    getState: function () {
+        return this.editor.getState();
+    },
+
+    setState: function (v) {
+        var o = this.options;
+        v = (BI.isEmpty(v) || v == o.text) ? o.text : v + "(" + o.text + ")";
+        this.editor.setState(v);
+    }
+});
+BI.SignInitialEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SignInitialEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SignInitialEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SignInitialEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SignInitialEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SignInitialEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SignInitialEditor.EVENT_START = "EVENT_START";
+BI.SignInitialEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SignInitialEditor.EVENT_STOP = "EVENT_STOP";
+BI.SignInitialEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SignInitialEditor.EVENT_VALID = "EVENT_VALID";
+BI.SignInitialEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SignInitialEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SignInitialEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SignInitialEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SignInitialEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.sign_initial_editor", BI.SignInitialEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.sign.style.js b/src/widget/base/editor/editor.sign.style.js
new file mode 100644
index 000000000..7f289ac72
--- /dev/null
+++ b/src/widget/base/editor/editor.sign.style.js
@@ -0,0 +1,260 @@
+/**
+ * sign标签分两段,可以自定义样式
+ * @class BI.SignStyleEditor
+ * @extends BI.Single
+ */
+BI.SignStyleEditor = BI.inherit(BI.Single, {
+
+    constants: {
+        tipTextGap: 4
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.SignStyleEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-sign-style-editor",
+            text: "",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: false,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.SignStyleEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.text = BI.createWidget({
+            type: "bi.text_button",
+            cls: "sign-style-editor-text",
+            textAlign: "left",
+            height: o.height,
+            hgap: 4,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.selectAll();
+            }
+        });
+
+        this.tipText = BI.createWidget({
+            type: "bi.text_button",
+            cls: "sign-style-editor-tip",
+            textAlign: "right",
+            rgap: 4,
+            height: o.height,
+            text: o.text,
+            handler: function () {
+                self._showInput();
+                self.editor.focus();
+                self.editor.selectAll();
+            }
+        });
+
+        this.text.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SignStyleEditor.EVENT_CLICK_LABEL)
+            });
+        });
+
+        this.tipText.on(BI.TextButton.EVENT_CHANGE, function () {
+            BI.nextTick(function () {
+                self.fireEvent(BI.SignStyleEditor.EVENT_CLICK_LABEL)
+            });
+        });
+
+        this.wrap = BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [this.text, this.tipText]
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.SignStyleEditor.EVENT_KEY_DOWN);
+        });
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self._showHint();
+            self._checkText();
+            self._resizeLayout();
+            self.fireEvent(BI.SignStyleEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.SignStyleEditor.EVENT_EMPTY);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+        this._showHint();
+        this._checkText();
+
+        BI.nextTick(function () {
+            var tipTextSize = self.text.element.getStyle("font-size");
+            self.tipTextSize = tipTextSize.substring(0, tipTextSize.length - 2);
+            self._resizeLayout();
+        });
+    },
+
+    _checkText: function () {
+        var o = this.options;
+        if (this.editor.getValue() === "") {
+            this.text.setValue(o.watermark || "");
+            this.text.element.addClass("bi-water-mark");
+        } else {
+            this.text.setValue(this.editor.getValue());
+            this.tipText.setValue("(" + o.text + ")");
+            this.text.element.removeClass("bi-water-mark");
+        }
+        this.setTitle(this.text.getValue() + this.tipText.getValue());
+    },
+
+    _showInput: function () {
+        this.editor.setVisible(true);
+        this.text.setVisible(false);
+        this.tipText.setVisible(false);
+    },
+
+    _showHint: function () {
+        this.editor.setVisible(false);
+        this.text.setVisible(true);
+        this.tipText.setVisible(true);
+    },
+
+    _resizeLayout: function () {
+        this.wrap.attr("items")[0].width = BI.DOM.getTextSizeWidth(this.text.getValue(), this.tipTextSize) + 2 * this.constants.tipTextGap;
+        this.wrap.resize();
+    },
+
+    focus: function () {
+        this._showInput();
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+        this._showHint();
+        this._checkText();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    setValue: function (k) {
+        BI.SignStyleEditor.superclass.setValue.apply(this, arguments);
+        this.editor.setValue(k);
+        this._checkText();
+        this._resizeLayout();
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    getState: function () {
+        return this.options.text;
+    },
+
+    setState: function (v) {
+        var o = this.options;
+        o.text = v;
+        this._showHint();
+        this.tipText.setValue("(" + v + ")");
+        this._checkText();
+    }
+});
+BI.SignStyleEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SignStyleEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.SignStyleEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.SignStyleEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.SignStyleEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.SignStyleEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL";
+
+BI.SignStyleEditor.EVENT_START = "EVENT_START";
+BI.SignStyleEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.SignStyleEditor.EVENT_STOP = "EVENT_STOP";
+BI.SignStyleEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.SignStyleEditor.EVENT_VALID = "EVENT_VALID";
+BI.SignStyleEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.SignStyleEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.SignStyleEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.SignStyleEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.SignStyleEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.sign_style_editor", BI.SignStyleEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.text.js b/src/widget/base/editor/editor.text.js
new file mode 100644
index 000000000..46a4476c3
--- /dev/null
+++ b/src/widget/base/editor/editor.text.js
@@ -0,0 +1,170 @@
+/**
+ * guy
+ * @class BI.TextEditor
+ * @extends BI.Single
+ */
+BI.TextEditor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.TextEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-text-editor",
+            hgap: 4,
+            vgap: 2,
+            lgap: 0,
+            rgap: 0,
+            tgap: 0,
+            bgap: 0,
+            validationChecker: BI.emptyFn,
+            quitChecker: BI.emptyFn,
+            mouseOut: false,
+            allowBlank: false,
+            watermark: "",
+            errorText: "",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.TextEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isNumber(o.height)) {
+            this.element.css({height: o.height - 2});
+        }
+        if (BI.isNumber(o.width)) {
+            this.element.css({width: o.width - 2});
+        }
+        this.editor = BI.createWidget({
+            type: "bi.editor",
+            height: o.height - 2,
+            hgap: o.hgap,
+            vgap: o.vgap,
+            lgap: o.lgap,
+            rgap: o.rgap,
+            tgap: o.tgap,
+            bgap: o.bgap,
+            value: o.value,
+            validationChecker: o.validationChecker,
+            quitChecker: o.quitChecker,
+            mouseOut: o.mouseOut,
+            allowBlank: o.allowBlank,
+            watermark: o.watermark,
+            errorText: o.errorText
+        });
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.TextEditor.EVENT_FOCUS);
+        });
+        this.editor.on(BI.Editor.EVENT_BLUR, function () {
+            self.fireEvent(BI.TextEditor.EVENT_BLUR);
+        });
+        this.editor.on(BI.Editor.EVENT_CLICK, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CLICK);
+        });
+        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CHANGE);
+        });
+        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_KEY_DOWN);
+        });
+        this.editor.on(BI.Editor.EVENT_SPACE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_SPACE);
+        });
+        this.editor.on(BI.Editor.EVENT_BACKSPACE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_BACKSPACE);
+        });
+
+
+        this.editor.on(BI.Editor.EVENT_VALID, function () {
+            self.fireEvent(BI.TextEditor.EVENT_VALID);
+        });
+        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
+            self.fireEvent(BI.TextEditor.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.Editor.EVENT_REMOVE, function (v) {
+            self.fireEvent(BI.TextEditor.EVENT_REMOVE);
+        });
+        this.editor.on(BI.Editor.EVENT_START, function () {
+            self.fireEvent(BI.TextEditor.EVENT_START);
+        });
+        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.TextEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.Editor.EVENT_STOP, function () {
+            self.fireEvent(BI.TextEditor.EVENT_STOP);
+        });
+        this.editor.on(BI.Editor.EVENT_ERROR, function () {
+            self.fireEvent(BI.TextEditor.EVENT_ERROR);
+        });
+        this.editor.on(BI.Editor.EVENT_ENTER, function () {
+            self.fireEvent(BI.TextEditor.EVENT_ENTER);
+        });
+        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
+            self.fireEvent(BI.TextEditor.EVENT_RESTRICT);
+        });
+        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
+            self.fireEvent(BI.TextEditor.EVENT_EMPTY);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            element: this,
+            items: [this.editor]
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    setErrorText: function (text) {
+        this.editor.setErrorText(text);
+    },
+
+    getErrorText: function () {
+        return this.editor.getErrorText();
+    },
+
+    isValid: function () {
+        return this.editor.isValid();
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    },
+
+    setEnable: function (b) {
+        BI.Editor.superclass.setEnable.apply(this, arguments);
+        this.editor && this.editor.setEnable(b);
+    }
+});
+BI.TextEditor.EVENT_CHANGE = "EVENT_CHANGE";
+BI.TextEditor.EVENT_FOCUS = "EVENT_FOCUS";
+BI.TextEditor.EVENT_BLUR = "EVENT_BLUR";
+BI.TextEditor.EVENT_CLICK = "EVENT_CLICK";
+BI.TextEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+BI.TextEditor.EVENT_SPACE = "EVENT_SPACE";
+BI.TextEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
+
+BI.TextEditor.EVENT_START = "EVENT_START";
+BI.TextEditor.EVENT_PAUSE = "EVENT_PAUSE";
+BI.TextEditor.EVENT_STOP = "EVENT_STOP";
+BI.TextEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.TextEditor.EVENT_VALID = "EVENT_VALID";
+BI.TextEditor.EVENT_ERROR = "EVENT_ERROR";
+BI.TextEditor.EVENT_ENTER = "EVENT_ENTER";
+BI.TextEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
+BI.TextEditor.EVENT_REMOVE = "EVENT_REMOVE";
+BI.TextEditor.EVENT_EMPTY = "EVENT_EMPTY";
+
+$.shortcut("bi.text_editor", BI.TextEditor);
\ No newline at end of file
diff --git a/src/widget/base/editor/editor.text.small.js b/src/widget/base/editor/editor.text.small.js
new file mode 100644
index 000000000..f0becab89
--- /dev/null
+++ b/src/widget/base/editor/editor.text.small.js
@@ -0,0 +1,20 @@
+/**
+ * 小号搜索框
+ * Created by GUY on 2015/9/29.
+ * @class BI.SmallTextEditor
+ * @extends BI.SearchEditor
+ */
+BI.SmallTextEditor = BI.inherit(BI.TextEditor, {
+    _defaultConfig: function () {
+        var conf = BI.SmallTextEditor.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-small-text-editor",
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.SmallTextEditor.superclass._init.apply(this, arguments);
+    }
+});
+$.shortcut("bi.small_text_editor", BI.SmallTextEditor);
\ No newline at end of file
diff --git a/src/widget/base/mask/cancel.loading.mask.js b/src/widget/base/mask/cancel.loading.mask.js
new file mode 100644
index 000000000..fe6662e67
--- /dev/null
+++ b/src/widget/base/mask/cancel.loading.mask.js
@@ -0,0 +1,83 @@
+/**
+ * @class BI.LoadingCancelMask
+ * @extend BI.Widget
+ * 带有取消按钮的正在加载mask
+ */
+BI.LoadingCancelMask = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingCancelMask.superclass._defaultConfig.apply(this, arguments), {})
+    },
+
+    _init: function () {
+        BI.LoadingCancelMask.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var cancelButton = BI.createWidget({
+            type: "bi.button",
+            level: "ignore",
+            width: 100,
+            height: 30,
+            text: BI.i18nText("BI-Basic_Cancel")
+        });
+        cancelButton.on(BI.Button.EVENT_CHANGE, function () {
+            self.fireEvent(BI.LoadingCancelMask.EVENT_VALUE_CANCEL);
+            self.destroy();
+        });
+        var mask = BI.Maskers.create(this.getName(), o.masker);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: mask,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    cls: "bi-loading-main-background"
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }, {
+                el: {
+                    type: "bi.center_adapt",
+                    cls: "bi-loading-mask-content",
+                    items: [{
+                        el: {
+                            type: "bi.vertical",
+                            items: [{
+                                type: "bi.center_adapt",
+                                cls: "loading-bar-icon",
+                                items: [{
+                                    type: "bi.icon",
+                                    width: 208,
+                                    height: 30
+                                }]
+                            }, {
+                                type: "bi.label",
+                                cls: "loading-bar-label",
+                                text: o.text,
+                                height: 30
+                            }, {
+                                type: "bi.center_adapt",
+                                items: [cancelButton]
+                            }],
+                            vgap: 10
+                        }
+                    }]
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+BI.LoadingCancelMask.EVENT_VALUE_CANCEL = "EVENT_VALUE_CANCEL";
+$.shortcut("bi.loading_cancel_mask", BI.LoadingCancelMask);
\ No newline at end of file
diff --git a/src/widget/base/mask/loading.background.js b/src/widget/base/mask/loading.background.js
new file mode 100644
index 000000000..937296bdd
--- /dev/null
+++ b/src/widget/base/mask/loading.background.js
@@ -0,0 +1,33 @@
+/**
+ * @class BI.LoadingBackground
+ * @extend BI.Widget
+ * 正在加载mask层
+ */
+BI.LoadingBackground = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingBackground.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "",
+            backgroundCls: "loading-background-e50"
+        })
+    },
+
+    _init: function () {
+        BI.LoadingBackground.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var mask = BI.Maskers.create(this.getName(), o.masker, {offset: o.offset, container: o.container});
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: mask,
+            cls: "bi-loading-mask " + o.backgroundCls
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+$.shortcut("bi.loading_background", BI.LoadingBackground);
\ No newline at end of file
diff --git a/src/widget/base/mask/loading.mask.js b/src/widget/base/mask/loading.mask.js
new file mode 100644
index 000000000..1423af0cc
--- /dev/null
+++ b/src/widget/base/mask/loading.mask.js
@@ -0,0 +1,67 @@
+/**
+ * @class BI.LoadingMask
+ * @extend BI.Widget
+ * 正在加载mask层
+ */
+BI.LoadingMask = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LoadingMask.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: ""
+        });
+    },
+
+    _init: function () {
+        BI.LoadingMask.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var mask = BI.Maskers.create(this.getName(), o.masker, {offset: o.offset, container: o.container});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: mask,
+            items: [{
+                el: {
+                    type: "bi.layout",
+                    cls: "bi-loading-main-background"
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }, {
+                el: {
+                    type: "bi.center_adapt",
+                    cls: "bi-loading-mask-content",
+                    items: [{
+                        type: "bi.vertical",
+                        items: [{
+                            type: "bi.center_adapt",
+                            cls: "loading-bar-icon",
+                            items: [{
+                                type: "bi.icon",
+                                width: 208,
+                                height: 30
+                            }]
+                        }, {
+                            type: "bi.label",
+                            cls: "loading-bar-label",
+                            text: o.text,
+                            height: 30
+                        }]
+                    }]
+                },
+                top: 0,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+        BI.Maskers.show(this.getName());
+        BI.nextTick(function () {
+            BI.Maskers.show(self.getName());
+        });
+    },
+
+    destroy: function () {
+        BI.Maskers.remove(this.getName());
+    }
+});
+$.shortcut("bi.loading_mask", BI.LoadingMask);
\ No newline at end of file
diff --git a/src/widget/base/segment/button.line.segment.js b/src/widget/base/segment/button.line.segment.js
new file mode 100644
index 000000000..04643ed5a
--- /dev/null
+++ b/src/widget/base/segment/button.line.segment.js
@@ -0,0 +1,63 @@
+/**
+ * 一个button选中的时候下面有条线
+ *
+ * Created by GUY on 2015/9/30.
+ * @class BI.LineSegmentButton
+ * @extends BI.BasicButton
+ */
+BI.LineSegmentButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function() {
+        var conf = BI.LineSegmentButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend( conf, {
+            baseCls : (conf.baseCls ||"")+' bi-line-segment-button bi-list-item-effect',
+            once: true,
+            readonly: true,
+            hgap: 10,
+            height: 25
+        })
+    },
+
+    _init:function() {
+        BI.LineSegmentButton.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            text: o.text,
+            height: o.height,
+            value: o.value,
+            hgap: o.hgap
+        });
+
+        this.line = BI.createWidget({
+            type: "bi.layout",
+            cls: "line-segment-button-line",
+            height: 3
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.line,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    setSelected: function(v){
+        BI.LineSegmentButton.superclass.setSelected.apply(this, arguments);
+    },
+
+    setText : function(text) {
+        BI.LineSegmentButton.superclass.setText.apply(this, arguments);
+        this.text.setText(text);
+    },
+
+    destroy : function() {
+        BI.LineSegmentButton.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.line_segment_button', BI.LineSegmentButton);
\ No newline at end of file
diff --git a/src/widget/base/segment/segment.line.js b/src/widget/base/segment/segment.line.js
new file mode 100644
index 000000000..af58cde5d
--- /dev/null
+++ b/src/widget/base/segment/segment.line.js
@@ -0,0 +1,62 @@
+/**
+ * 另一套风格的单选按钮组
+ *
+ * Created by GUY on 2015/9/30.
+ * @class BI.LineSegment
+ * @extends BI.Widget
+ */
+BI.LineSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.LineSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-line-segment",
+            items: [],
+            height: 30
+        });
+    },
+    _init: function () {
+        BI.LineSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        if (BI.isNumber(o.height)) {
+            this.element.css({height: o.height - 1, lineHeight: (o.height - 1) + 'px'});
+        }
+        this.buttonGroup = BI.createWidget({
+            element: this,
+            type: "bi.button_group",
+            items: BI.createItems(o.items, {
+                type: "bi.line_segment_button",
+                height: o.height - 1
+            }),
+            layout: [
+                {
+                    type: "bi.center"
+                }
+            ]
+        });
+        this.buttonGroup.on(BI.Controller.EVENT_CHANGE, function(){
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments)
+        });
+        this.buttonGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.LineSegment.EVENT_CHANGE)
+        })
+    },
+
+    setValue: function (v) {
+        this.buttonGroup.setValue(v);
+    },
+
+    setEnabledValue: function (v) {
+        this.buttonGroup.setEnabledValue(v);
+    },
+
+    setEnable: function (v) {
+        BI.LineSegment.superclass.setEnable.apply(this, arguments);
+        this.buttonGroup.setEnable(v)
+    },
+
+
+    getValue: function () {
+        return this.buttonGroup.getValue();
+    }
+});
+BI.LineSegment.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.line_segment', BI.LineSegment);
\ No newline at end of file
diff --git a/src/widget/base/tip/tip.helper.js b/src/widget/base/tip/tip.helper.js
new file mode 100644
index 000000000..5c9ea660e
--- /dev/null
+++ b/src/widget/base/tip/tip.helper.js
@@ -0,0 +1,46 @@
+/**
+ * 拖拽字段的helper
+ * Created by roy on 15/10/13.
+ */
+BI.Helper = BI.inherit(BI.Tip, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Helper.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-helper",
+            text: "",
+            value: ""
+        })
+    },
+
+    _init: function () {
+        BI.Helper.superclass._init.apply(this, arguments);
+        this.populate();
+    },
+
+    modifyContent: function(widget) {
+        this.empty();
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            cls: "dragging-modify",
+            items: [widget],
+            lgap: 15
+        });
+    },
+
+    populate: function () {
+        var o = this.options;
+        this.element.data({helperWidget: this});
+        this.empty();
+        BI.createWidget({
+            element: this,
+            type: "bi.label",
+            textAlign: "center",
+            textHeight: 20,
+            hgap: 5,
+            text: o.text,
+            value: o.value
+        });
+        this.element.removeClass("dragging-modify");
+    }
+});
+$.shortcut("bi.helper", BI.Helper);
\ No newline at end of file
diff --git a/src/widget/base/toolbar/toolbar.progress.bar.js b/src/widget/base/toolbar/toolbar.progress.bar.js
new file mode 100644
index 000000000..09454a6bc
--- /dev/null
+++ b/src/widget/base/toolbar/toolbar.progress.bar.js
@@ -0,0 +1,50 @@
+/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBarBar
+ * @extends BI.BasicButton
+ */
+BI.ProgressBarBar = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBarBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar-bar",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBarBar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.svg = BI.createWidget({
+            type: "bi.svg",
+            width: 6,
+            height: 6
+        });
+        this.svg.circle(3, 3, 3).attr({fill: "#ffffff", "stroke": ""});
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.svg,
+                right: 10,
+                top: 9
+            }]
+        });
+        this.processor = BI.createWidget({
+            type: "bi.progress_bar_processor",
+            width: "0%",
+            height: o.height
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.processor]
+        });
+    },
+
+    setValue: function (process) {
+        this.processor.setValue(process);
+
+    }
+});
+$.shortcut("bi.progress_bar_bar", BI.ProgressBarBar);
\ No newline at end of file
diff --git a/src/widget/base/toolbar/toolbar.progress.js b/src/widget/base/toolbar/toolbar.progress.js
new file mode 100644
index 000000000..10d3904c1
--- /dev/null
+++ b/src/widget/base/toolbar/toolbar.progress.js
@@ -0,0 +1,52 @@
+/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBar
+ * @extends BI.BasicButton
+ */
+BI.ProgressBar = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.bar = BI.createWidget({
+            type: "bi.progress_bar_bar",
+            height: o.height
+        });
+        this.label = BI.createWidget({
+            type: "bi.label",
+            cls: "progress-bar-label",
+            width: 50,
+            height: o.height,
+            value: "0%"
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.bar
+            }, {
+                el: this.label,
+                width: 50
+            }]
+        })
+    },
+
+    setValue: function (process) {
+        if (process >= 100) {
+            process = 100;
+            this.label.element.addClass("success");
+        } else {
+            this.label.element.removeClass("success");
+        }
+        this.label.setValue(process + "%");
+        this.bar.setValue(process);
+    }
+});
+$.shortcut("bi.progress_bar", BI.ProgressBar);
\ No newline at end of file
diff --git a/src/widget/base/toolbar/toolbar.progress.processor.js b/src/widget/base/toolbar/toolbar.progress.processor.js
new file mode 100644
index 000000000..b520489cb
--- /dev/null
+++ b/src/widget/base/toolbar/toolbar.progress.processor.js
@@ -0,0 +1,50 @@
+/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/12/24.
+ * @class BI.ProgressBarProcessor
+ * @extends BI.BasicButton
+ */
+BI.ProgressBarProcessor = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ProgressBarProcessor.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-progress-bar-processor",
+            height: 24
+        })
+    },
+    _init: function () {
+        BI.ProgressBarProcessor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.svg = BI.createWidget({
+            type: "bi.svg",
+            width: 12,
+            height: 12
+        });
+        this.svg.circle(6, 6, 6).attr({fill: "#eaeaea", "stroke": ""});
+
+        this.dot = this.svg.circle(6, 6, 3).attr({fill: "#ffffff", "stroke": ""}).hide();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.svg,
+                right: 7,
+                top: 6
+            }]
+        });
+    },
+
+    setValue: function (process) {
+        if (process >= 100) {
+            process = 100;
+            this.dot.show();
+            this.element.addClass("success");
+        } else {
+            this.dot.hide();
+            this.element.removeClass("success");
+        }
+        this.element.width(process + "%");
+    }
+});
+BI.ProgressBarProcessor.EVENT_CHANGE = "ProgressBarProcessor.EVENT_CHANGE";
+$.shortcut("bi.progress_bar_processor", BI.ProgressBarProcessor);
\ No newline at end of file
diff --git a/src/widget/branchrelation/branchrelation.js b/src/widget/branchrelation/branchrelation.js
new file mode 100644
index 000000000..5a3e9a8c7
--- /dev/null
+++ b/src/widget/branchrelation/branchrelation.js
@@ -0,0 +1,498 @@
+/**
+ * 表关联树
+ *
+ * Created by GUY on 2015/12/15.
+ * @class BI.BranchRelation
+ * @extends BI.Widget
+ */
+BI.BranchRelation = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.BranchRelation.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-branch-relation-tree",
+            items: [],
+
+            centerOffset: 0,//重心偏移量
+            direction: BI.Direction.Bottom,
+            align: BI.VerticalAlign.Top
+        })
+    },
+
+    _init: function () {
+        BI.BranchRelation.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    //树分层
+    _stratification: function () {
+        var levels = [];
+        this.tree.recursion(function (node, route) {
+            //node.isRoot = route.length <= 1;
+            node.leaf = node.isLeaf();
+            if (!levels[route.length - 1]) {
+                levels[route.length - 1] = [];
+            }
+            levels[route.length - 1].push(node);
+        });
+        return levels;
+    },
+
+    //计算所有节点的叶子结点个数
+    _calculateLeaves: function () {
+        var count = 0;
+
+        function track(node) {
+            var c = 0;
+            if (node.isLeaf()) {
+                return 1;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                c += track(child);
+            });
+            node.set("leaves", c);
+            return c;
+        }
+
+        count = track(this.tree.getRoot());
+        return count;
+    },
+
+    //树平移
+    _translate: function (levels) {
+        var adjust = [];
+        var maxLevel = levels.length;
+        BI.each(levels, function (i, nodes) {
+            if (!adjust[i]) {
+                adjust[i] = [];
+            }
+            BI.each(nodes, function (j, node) {
+                if (node.isLeaf() && i < maxLevel - 1) {
+                    var newNode = new BI.Node(BI.UUID());
+                    //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot;
+                    newNode.isNew = true;
+                    //把node向下一层移
+                    var tar = 0;
+                    if (j > 0) {
+                        var c = nodes[j - 1].getLastChild();
+                        tar = levels[i + 1].indexOf(c) + 1;
+                    }
+                    levels[i + 1].splice(tar, 0, node);
+                    //新增一个临时树节点
+                    var index = node.parent.getChildIndex(node.id);
+                    node.parent.removeChildByIndex(index);
+                    node.parent.addChild(newNode, index);
+                    newNode.addChild(node);
+                    adjust[i].push(newNode);
+                    nodes[j] = newNode;
+                } else {
+                    adjust[i].push(node);
+                }
+            })
+        });
+        return adjust;
+    },
+
+    //树补白
+    _fill: function (levels) {
+        var adjust = [];
+        var maxLevel = levels.length;
+        BI.each(levels, function (i, nodes) {
+            if (!adjust[i]) {
+                adjust[i] = [];
+            }
+            BI.each(nodes, function (j, node) {
+                if (node.isLeaf() && i < maxLevel - 1) {
+                    var newNode = new BI.Node(BI.UUID());
+                    newNode.leaf = true;
+                    newNode.width = node.width;
+                    newNode.height = node.height;
+                    newNode.isNew = true;
+                    //把node向下一层移
+                    var tar = 0;
+                    if (j > 0) {
+                        var c = nodes[j - 1].getLastChild();
+                        tar = levels[i + 1].indexOf(c) + 1;
+                    }
+                    levels[i + 1].splice(tar, 0, newNode);
+                    //新增一个临时树节点
+                    node.addChild(newNode);
+                }
+                adjust[i].push(node);
+            })
+        });
+        return adjust;
+    },
+
+    //树调整
+    _adjust: function (adjust) {
+        while (true) {
+            var isAllNeedAjust = false;
+            BI.backEach(adjust, function (i, nodes) {
+                BI.each(nodes, function (j, node) {
+                    if (!node.isNew) {
+                        var needAdjust = true;
+                        BI.any(node.getChildren(), function (k, n) {
+                            if (!n.isNew) {
+                                needAdjust = false;
+                                return true;
+                            }
+                        });
+                        if (!node.isLeaf() && needAdjust === true) {
+                            var allChilds = [];
+                            BI.each(node.getChildren(), function (k, n) {
+                                allChilds = allChilds.concat(n.getChildren());
+                            });
+                            node.removeAllChilds();
+                            BI.each(allChilds, function (k, c) {
+                                node.addChild(c);
+                            });
+                            var newNode = new BI.Node(BI.UUID());
+                            //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot;
+                            newNode.isNew = true;
+                            var index = node.parent.getChildIndex(node.id);
+                            node.parent.removeChildByIndex(index);
+                            node.parent.addChild(newNode, index);
+                            newNode.addChild(node);
+                            isAllNeedAjust = true;
+                        }
+                    }
+                })
+            });
+            if (isAllNeedAjust === false) {
+                break;
+            } else {//树重构
+                adjust = this._stratification();
+            }
+        }
+        return adjust;
+    },
+
+    _calculateWidth: function () {
+        var o = this.options;
+        var width = 0;
+
+        function track1(node) {
+            var w = 0;
+            if (node.isLeaf()) {
+                return node.width;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                w += track1(child);
+            });
+            return w;
+        }
+
+        function track2(node) {
+            var w = 0;
+            if (node.isLeaf()) {
+                return node.height;
+            }
+            BI.each(node.getChildren(), function (i, child) {
+                w += track2(child);
+            });
+            return w;
+        }
+
+        if (this._isVertical()) {
+            width = track1(this.tree.getRoot());
+        } else {
+            width = track2(this.tree.getRoot());
+        }
+
+        return width;
+    },
+
+    _isVertical: function () {
+        var o = this.options;
+        return o.direction === BI.Direction.Top || o.direction === BI.Direction.Bottom;
+    },
+
+    _calculateHeight: function () {
+        var o = this.options;
+        var height = 0;
+
+        function track1(node) {
+            var h = 0;
+            BI.each(node.getChildren(), function (i, child) {
+                h = Math.max(h, track1(child));
+            });
+            return h + (node.height || 0);
+        }
+
+        function track2(node) {
+            var h = 0;
+            BI.each(node.getChildren(), function (i, child) {
+                h = Math.max(h, track2(child));
+            });
+            return h + (node.width || 0);
+        }
+
+        if (this._isVertical()) {
+            height = track1(this.tree.getRoot());
+        } else {
+            height = track2(this.tree.getRoot());
+        }
+        return height;
+    },
+
+    _calculateXY: function (levels) {
+        var o = this.options;
+        var width = this._calculateWidth();
+        var height = this._calculateHeight();
+        var levelCount = levels.length;
+        var allLeavesCount = this._calculateLeaves();
+        //计算坐标
+        var xy = {};
+        var levelHeight = height / levelCount;
+        BI.each(levels, function (i, nodes) {
+            //计算权重
+            var weights = [];
+            BI.each(nodes, function (j, node) {
+                weights[j] = (node.get("leaves") || 1) / allLeavesCount;
+            });
+            BI.each(nodes, function (j, node) {
+                //求前j个元素的权重
+                var weight = BI.sum(weights.slice(0, j));
+                //求坐标
+                var x = weight * width + weights[j] * width / 2;
+                var y = i * levelHeight + levelHeight / 2;
+                xy[node.id] = {x: x, y: y};
+            })
+        });
+        return xy;
+    },
+
+    _stroke: function (levels, xy) {
+        var height = this._calculateHeight();
+        var levelCount = levels.length;
+        var levelHeight = height / levelCount;
+        var self = this, o = this.options;
+        switch (o.direction) {
+            case BI.Direction.Top:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y + levelHeight / 2;
+                            path += "M" + start.x + "," + (start.y + o.centerOffset) + "L" + start.x + "," + split;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + e.x + "," + (e.y + o.centerOffset) + "L" + e.x + "," + split;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Bottom:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y - levelHeight / 2;
+                            path += "M" + start.x + "," + (start.y - o.centerOffset) + "L" + start.x + "," + split;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + e.x + "," + (e.y - o.centerOffset) + "L" + e.x + "," + split;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Left:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y + levelHeight / 2;
+                            path += "M" + (start.y + o.centerOffset) + "," + start.x + "L" + split + "," + start.x;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + (e.y + o.centerOffset) + "," + e.x + "L" + split + "," + e.x;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+            case BI.Direction.Right:
+                BI.each(levels, function (i, nodes) {
+                    BI.each(nodes, function (j, node) {
+                        if (node.getChildrenLength() > 0 && !node.leaf) {
+                            var path = "";
+                            var start = xy[node.id];
+                            var split = start.y - levelHeight / 2;
+                            path += "M" + (start.y - o.centerOffset) + "," + start.x + "L" + split + "," + start.x;
+                            var end = [];
+                            BI.each(node.getChildren(), function (t, c) {
+                                var e = end[t] = xy[c.id];
+                                path += "M" + (e.y - o.centerOffset) + "," + e.x + "L" + split + "," + e.x;
+                            });
+                            if (end.length > 0) {
+                                path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x;
+                            }
+                            self.svg.path(path).attr("stroke", "gray");
+                        }
+                    })
+                });
+                break;
+        }
+    },
+
+    _createBranches: function (levels) {
+        var self = this, o = this.options;
+        if (o.direction === BI.Direction.Bottom || o.direction === BI.Direction.Right) {
+            levels = levels.reverse();
+        }
+        var xy = this._calculateXY(levels);
+        //画图
+        this._stroke(levels, xy);
+    },
+
+    _isNeedAdjust: function () {
+        var o = this.options;
+        return o.direction === BI.Direction.Top && o.align === BI.VerticalAlign.Bottom || o.direction === BI.Direction.Bottom && o.align === BI.VerticalAlign.Top
+            || o.direction === BI.Direction.Left && o.align === BI.HorizontalAlign.Right || o.direction === BI.Direction.Right && o.align === BI.HorizontalAlign.Left
+    },
+
+    setValue: function (value) {
+
+    },
+
+    getValue: function () {
+
+    },
+
+    _transformToTreeFormat: function (sNodes) {
+        var i, l;
+        if (!sNodes) {
+            return [];
+        }
+
+        if (BI.isArray(sNodes)) {
+            var r = [];
+            var tmpMap = [];
+            for (i = 0, l = sNodes.length; i < l; i++) {
+                tmpMap[sNodes[i].id] = sNodes[i];
+            }
+            for (i = 0, l = sNodes.length; i < l; i++) {
+                if (tmpMap[sNodes[i].pId] && sNodes[i].id != sNodes[i].pId) {
+                    if (!tmpMap[sNodes[i].pId].children) {
+                        tmpMap[sNodes[i].pId].children = [];
+                    }
+                    tmpMap[sNodes[i].pId].children.push(sNodes[i]);
+                } else {
+                    r.push(sNodes[i]);
+                }
+            }
+            return r;
+        } else {
+            return [sNodes];
+        }
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options;
+        o.items = items || [];
+        this.empty();
+        items = this._transformToTreeFormat(o.items);
+        this.tree = new BI.Tree();
+        this.tree.initTree(items);
+
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+
+        //树分层
+        var levels = this._stratification();
+
+        if (this._isNeedAdjust()) {
+            //树平移
+            var adjust = this._translate(levels);
+            //树调整
+            adjust = this._adjust(adjust);
+
+            this._createBranches(adjust);
+        } else {
+            var adjust = this._fill(levels);
+
+            this._createBranches(adjust);
+        }
+
+        var container = BI.createWidget({
+            type: "bi.layout",
+            width: this._isVertical() ? this._calculateWidth() : this._calculateHeight(),
+            height: this._isVertical() ? this._calculateHeight() : this._calculateWidth()
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container,
+            items: [{
+                el: this.svg,
+                top: 0,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        });
+        if (this._isVertical()) {
+            items = [{
+                type: "bi.handstand_branch_tree",
+                expander: {
+                    direction: o.direction
+                },
+                el: {
+                    layouts: [{
+                        type: "bi.horizontal_adapt",
+                        verticalAlign: o.align
+                    }]
+                },
+                items: items
+            }]
+        } else {
+            items = [{
+                type: "bi.branch_tree",
+                expander: {
+                    direction: o.direction
+                },
+                el: {
+                    layouts: [{
+                        type: "bi.vertical"
+                    }, {
+                        type: o.align === BI.HorizontalAlign.Left ? "bi.left" : "bi.right"
+                    }]
+                },
+                items: items
+            }]
+        }
+        BI.createWidget({
+            type: "bi.adaptive",
+            element: container,
+            items: items
+        });
+        BI.createWidget({
+            type: "bi.center_adapt",
+            scrollable: true,
+            element: this,
+            items: [container]
+        });
+    }
+});
+BI.BranchRelation.EVENT_CHANGE = "BranchRelation.EVENT_CHANGE";
+$.shortcut("bi.branch_relation", BI.BranchRelation);
\ No newline at end of file
diff --git a/src/widget/colorchooser/colorchooser.custom.js b/src/widget/colorchooser/colorchooser.custom.js
new file mode 100644
index 000000000..bdbe63115
--- /dev/null
+++ b/src/widget/colorchooser/colorchooser.custom.js
@@ -0,0 +1,70 @@
+/**
+ * 自定义选色
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.CustomColorChooser
+ * @extends BI.Widget
+ */
+BI.CustomColorChooser = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.CustomColorChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-custom-color-chooser",
+            width: 227,
+            height: 245
+        })
+    },
+
+    _init: function () {
+        BI.CustomColorChooser.superclass._init.apply(this, arguments);
+        var self = this;
+        this.editor = BI.createWidget({
+            type: "bi.color_picker_editor",
+            width: 195
+        });
+        this.editor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+        });
+        this.farbtastic = BI.createWidget({
+            type: "bi.farbtastic"
+        });
+        this.farbtastic.on(BI.Farbtastic.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                type: "bi.absolute",
+                items: [{
+                    el: this.editor,
+                    left: 15,
+                    top: 10,
+                    right: 15
+                }],
+                height: 30
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.farbtastic,
+                    left: 15,
+                    right: 15,
+                    top: 10
+                }],
+                height: 215
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.editor.setValue(color);
+        this.farbtastic.setValue(color);
+    },
+
+    getValue: function () {
+        return this.editor.getValue();
+    }
+});
+BI.CustomColorChooser.EVENT_CHANGE = "CustomColorChooser.EVENT_CHANGE";
+$.shortcut("bi.custom_color_chooser", BI.CustomColorChooser);
\ No newline at end of file
diff --git a/src/widget/colorchooser/colorchooser.js b/src/widget/colorchooser/colorchooser.js
new file mode 100644
index 000000000..4e93f1bc0
--- /dev/null
+++ b/src/widget/colorchooser/colorchooser.js
@@ -0,0 +1,86 @@
+/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooser
+ * @extends BI.Widget
+ */
+BI.ColorChooser = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-chooser",
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(BI.extend({
+            type: "bi.color_chooser_trigger",
+            width: o.width,
+            height: o.height
+        }, o.el));
+        this.colorPicker = BI.createWidget({
+            type: "bi.color_chooser_popup"
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 1,
+            el: this.trigger,
+            popup: {
+                el: this.colorPicker,
+                stopPropagation: false,
+                minWidth: 202
+            }
+        });
+
+        var fn = function () {
+            var color = self.colorPicker.getValue();
+            self.trigger.setValue(color);
+            var colors = BI.string2Array(BI.Cache.getItem("colors") || "");
+            var que = new BI.Queue(8);
+            que.fromArray(colors);
+            que.remove(color);
+            que.unshift(color);
+            BI.Cache.setItem("colors", BI.array2String(que.toArray()));
+        };
+
+        this.colorPicker.on(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, function () {
+            fn();
+        });
+
+        this.colorPicker.on(BI.ColorChooserPopup.EVENT_CHANGE, function () {
+            fn();
+            self.combo.hideView();
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.colorPicker.setStoreColors(BI.string2Array(BI.Cache.getItem("colors") || ""));
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.fireEvent(BI.ColorChooser.EVENT_CHANGE, arguments);
+        })
+    },
+
+    isViewVisible: function () {
+        return this.combo.isViewVisible();
+    },
+
+    setEnable: function (v) {
+        this.combo.setEnable(v)
+    },
+
+    setValue: function (color) {
+        this.combo.setValue(color);
+    },
+
+    getValue: function () {
+        return this.colorPicker.getValue();
+    }
+});
+BI.ColorChooser.EVENT_CHANGE = "ColorChooser.EVENT_CHANGE";
+$.shortcut("bi.color_chooser", BI.ColorChooser);
\ No newline at end of file
diff --git a/src/widget/colorchooser/colorchooser.popup.js b/src/widget/colorchooser/colorchooser.popup.js
new file mode 100644
index 000000000..6c9a7e40a
--- /dev/null
+++ b/src/widget/colorchooser/colorchooser.popup.js
@@ -0,0 +1,194 @@
+/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooserPopup
+ * @extends BI.Widget
+ */
+BI.ColorChooserPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ColorChooserPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-color-chooser-popup",
+            height: 145
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooserPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.colorEditor = BI.createWidget({
+            type: "bi.color_picker_editor"
+        });
+
+        this.colorEditor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () {
+            self.setValue(this.getValue());
+            self.fireEvent(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, arguments);
+        });
+
+        this.storeColors = BI.createWidget({
+            type: "bi.color_picker",
+            items: [[{
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }, {
+                value: "",
+                disabled: true
+            }]],
+            width: 190,
+            height: 25
+        });
+        this.storeColors.on(BI.ColorPicker.EVENT_CHANGE, function () {
+            self.setValue(this.getValue()[0]);
+            self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+        });
+
+        this.colorPicker = BI.createWidget({
+            type: "bi.color_picker",
+            width: 190,
+            height: 50
+        });
+
+        this.colorPicker.on(BI.ColorPicker.EVENT_CHANGE, function () {
+            self.setValue(this.getValue()[0]);
+            self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+        });
+
+        this.customColorChooser = BI.createWidget({
+            type: "bi.custom_color_chooser"
+        });
+
+        var panel = BI.createWidget({
+            type: "bi.popup_panel",
+            buttons: [BI.i18nText("BI-Basic_Cancel"), BI.i18nText("BI-Basic_Save")],
+            title: BI.i18nText("BI-Custom_Color"),
+            el: this.customColorChooser,
+            stopPropagation: false,
+            bgap: -1,
+            rgap: 1,
+            lgap: 1,
+            minWidth: 227
+        });
+
+        this.more = BI.createWidget({
+            type: "bi.combo",
+            direction: "right,top",
+            isNeedAdjustHeight: false,
+            el: {
+                type: "bi.text_item",
+                cls: "color-chooser-popup-more",
+                textAlign: "center",
+                height: 20,
+                text: BI.i18nText("BI-Basic_More") + "..."
+            },
+            popup: panel
+        });
+
+        this.more.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.customColorChooser.setValue(self.getValue());
+        });
+        panel.on(BI.PopupPanel.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.more.hideView();
+                    break;
+                case 1:
+                    self.setValue(self.customColorChooser.getValue());
+                    self.more.hideView();
+                    self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments);
+                    break;
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    cls: "color-chooser-popup-title",
+                    items: [{
+                        el: this.colorEditor,
+                        left: 0,
+                        right: 0,
+                        top: 5
+                    }]
+                },
+                height: 30
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.storeColors,
+                        left: 5,
+                        right: 5,
+                        top: 5
+                    }]
+                },
+                height: 30
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.colorPicker,
+                        left: 5,
+                        right: 5,
+                        top: 5
+                    }]
+                },
+                height: 65
+            }, {
+                el: this.more,
+                height: 20
+            }]
+        })
+    },
+
+    setStoreColors: function (colors) {
+        if (BI.isArray(colors)) {
+            var items = BI.map(colors, function (i, color) {
+                return {
+                    value: color
+                }
+            });
+            BI.count(colors.length, 8, function (i) {
+                items.push({
+                    value: "",
+                    disabled: true
+                })
+            });
+            this.storeColors.populate([items]);
+        }
+    },
+
+    setValue: function (color) {
+        this.colorEditor.setValue(color);
+        this.colorPicker.setValue(color);
+        this.storeColors.setValue(color);
+    },
+
+    getValue: function () {
+        return this.colorEditor.getValue();
+    }
+});
+BI.ColorChooserPopup.EVENT_VALUE_CHANGE = "ColorChooserPopup.EVENT_VALUE_CHANGE";
+BI.ColorChooserPopup.EVENT_CHANGE = "ColorChooserPopup.EVENT_CHANGE";
+$.shortcut("bi.color_chooser_popup", BI.ColorChooserPopup);
\ No newline at end of file
diff --git a/src/widget/colorchooser/colorchooser.trigger.js b/src/widget/colorchooser/colorchooser.trigger.js
new file mode 100644
index 000000000..5eb440aba
--- /dev/null
+++ b/src/widget/colorchooser/colorchooser.trigger.js
@@ -0,0 +1,58 @@
+/**
+ * 选色控件
+ *
+ * Created by GUY on 2015/11/17.
+ * @class BI.ColorChooserTrigger
+ * @extends BI.Trigger
+ */
+BI.ColorChooserTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        var conf = BI.ColorChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-color-chooser-trigger",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.ColorChooserTrigger.superclass._init.apply(this, arguments);
+        this.colorContainer = BI.createWidget({
+            type: "bi.layout"
+        });
+
+        var down = BI.createWidget({
+            type: "bi.icon_button",
+            disableSelected: true,
+            cls: "icon-combo-down-icon trigger-triangle-font",
+            width: 12,
+            height: 8
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.colorContainer,
+                left: 3,
+                right: 3,
+                top: 3,
+                bottom: 3
+            }, {
+                el: down,
+                right: 3,
+                bottom: 3
+            }]
+        });
+        if (this.options.value) {
+            this.setValue(this.options.value);
+        }
+    },
+
+    setValue: function (color) {
+        BI.ColorChooserTrigger.superclass.setValue.apply(this, arguments);
+        this.colorContainer.element.css("background-color", color);
+    }
+});
+BI.ColorChooserTrigger.EVENT_CHANGE = "ColorChooserTrigger.EVENT_CHANGE";
+$.shortcut("bi.color_chooser_trigger", BI.ColorChooserTrigger);
\ No newline at end of file
diff --git a/src/widget/copy2group/button.add.copy2group.js b/src/widget/copy2group/button.add.copy2group.js
new file mode 100644
index 000000000..b7af1bbbf
--- /dev/null
+++ b/src/widget/copy2group/button.add.copy2group.js
@@ -0,0 +1,59 @@
+/**
+ * 新建并选中某个分组按钮
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupAddButton
+ * @extends BI.BasicButton
+ */
+BI.Copy2GroupAddButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.Copy2GroupAddButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + ' bi-copy2group-add-button',
+            shadow: true,
+            isShadowShowingOnSelected: true,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.Copy2GroupAddButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            text: BI.i18nText("BI-Create_And_Select") + "\"江苏\"",
+            height: o.height
+        })
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "move2group-add-font"
+                },
+                width: 30
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    setValue: function (v) {
+        this.text.setValue(BI.i18nText("BI-Create_And_Select") + "\"" + v + "\"");
+        this.setTitle(BI.i18nText("BI-Create_And_Select") + "\"" + v + "\"", {
+            container: "body"
+        });
+    },
+
+    doClick: function () {
+        BI.Copy2GroupAddButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.Copy2GroupAddButton.EVENT_CHANGE);
+        }
+    }
+});
+BI.Copy2GroupAddButton.EVENT_CHANGE = "Copy2GroupAddButton.EVENT_CHANGE";
+$.shortcut('bi.copy2group_add_button', BI.Copy2GroupAddButton);
\ No newline at end of file
diff --git a/src/widget/copy2group/combo.copy2group.js b/src/widget/copy2group/combo.copy2group.js
new file mode 100644
index 000000000..c8384f25c
--- /dev/null
+++ b/src/widget/copy2group/combo.copy2group.js
@@ -0,0 +1,153 @@
+/**
+ * 复制到分组下拉框
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupCombo
+ * @extends BI.Widget
+ */
+BI.Copy2GroupCombo = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Copy2GroupCombo.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-copy2group-combo",
+            height: 30,
+            tipType: "warning",
+            items: []
+        });
+    },
+    _init: function () {
+        BI.Copy2GroupCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.button",
+            text: BI.i18nText("BI-Copy_To_Group"),
+            height: o.height
+        });
+
+        this.tools = BI.createWidget({
+            type: "bi.copy2group_bar"
+        });
+
+        this.tools.on(BI.Copy2GroupBar.EVENT_START, function () {
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_EMPTY, function () {
+            self.combo.adjustHeight();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_CLICK_BUTTON, function () {
+            self.fireEvent(BI.Copy2GroupCombo.EVENT_CLICK_BUTTON);
+            self.searcher.stopSearch();
+        });
+        this.tools.on(BI.Copy2GroupBar.EVENT_CHANGE, function () {
+            this.setButtonVisible(!self.searcher.hasMatched());
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+
+        this.popup = this._createPopup(this.options.items);
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: this.tools,
+            chooseType: BI.Selection.Multi,
+            adapter: this.popup
+        });
+
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+
+        });
+
+        this.multipopup = BI.createWidget({
+            type: "bi.multi_popup_view",
+            width: 200,
+            stopPropagation: false,
+            el: this.popup,
+            tool: this.searcher
+        });
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            isNeedAdjustWidth: false,
+            element: this,
+            el: this.trigger,
+            popup: this.multipopup
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.searcher.stopSearch();
+        });
+
+        this.multipopup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (value) {
+            switch (value) {
+                case 0 :
+                    self.fireEvent(BI.Copy2GroupCombo.EVENT_CONFIRM);
+                    self.combo.hideView();
+                    break;
+                default :
+                    break;
+            }
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            height: 25,
+            handler: function (v) {
+
+            }
+        })
+    },
+
+    _createPopup: function (items, opt) {
+        return BI.createWidget(BI.extend({
+            type: "bi.button_group",
+            items: this._createItems(items),
+            chooseType: 1,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        }, opt));
+    },
+
+
+    scrollToBottom: function () {
+        var self = this;
+        BI.delay(function () {
+            self.popup.element.scrollTop(BI.MAX);
+        }, 30);
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.combo.populate(this._createItems(items));
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+        this.searcher.setValue(v);
+    },
+
+    setEnable: function (enable) {
+        this.combo.setEnable.apply(this.combo, arguments);
+    },
+
+    getTargetValue: function () {
+        return this.tools.getValue();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    }
+});
+BI.Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW = "Copy2GroupCombo.EVENT_BEFORE_POPUPVIEW";
+BI.Copy2GroupCombo.EVENT_CHANGE = "Copy2GroupCombo.EVENT_CHANGE";
+BI.Copy2GroupCombo.EVENT_CONFIRM = "Copy2GroupCombo.EVENT_CONFIRM";
+BI.Copy2GroupCombo.EVENT_CLICK_BUTTON = "Copy2GroupCombo.EVENT_CLICK_BUTTON";
+$.shortcut('bi.copy2group_combo', BI.Copy2GroupCombo);
\ No newline at end of file
diff --git a/src/widget/copy2group/toolbar.copy2group.js b/src/widget/copy2group/toolbar.copy2group.js
new file mode 100644
index 000000000..b5b3fa277
--- /dev/null
+++ b/src/widget/copy2group/toolbar.copy2group.js
@@ -0,0 +1,85 @@
+/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/9/25.
+ * @class BI.Copy2GroupBar
+ * @extends BI.Widget
+ */
+BI.Copy2GroupBar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Copy2GroupBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-copy2group-bar"
+        })
+    },
+    _init: function () {
+        BI.Copy2GroupBar.superclass._init.apply(this, arguments);
+        var self = this;
+        this.search = BI.createWidget({
+            type: "bi.text_editor",
+            watermark: BI.i18nText("BI-Search_And_Create_Group"),
+            allowBlank: true
+        });
+
+        this.search.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+
+        this.search.on(BI.TextEditor.EVENT_CHANGE, function () {
+            self.button.setValue(this.getValue());
+            if(this.getValue() !== "") {
+                self.fireEvent(BI.Copy2GroupBar.EVENT_CHANGE);
+            }
+        });
+
+        this.search.on(BI.TextEditor.EVENT_EMPTY, function () {
+            self.button.invisible();
+            self.fireEvent(BI.Copy2GroupBar.EVENT_EMPTY);
+        });
+
+        this.search.on(BI.TextEditor.EVENT_START, function () {
+            self.button.visible();
+            self.fireEvent(BI.Copy2GroupBar.EVENT_START);
+        });
+
+        this.button = BI.createWidget({
+            type: "bi.copy2group_add_button"
+        });
+
+        this.button.on(BI.Copy2GroupAddButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Copy2GroupBar.EVENT_CLICK_BUTTON);
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            vgap: 5,
+            hgap: 5,
+            items: [this.search, this.button]
+        });
+
+        this.button.invisible();
+    },
+
+    blur: function(){
+        this.search.blur();
+    },
+
+    setButtonVisible: function (b) {
+        this.button.setVisible(b);
+    },
+
+    getValue: function () {
+        return this.search.getValue();
+    },
+
+    setValue: function (v) {
+        this.search.setValue(v);
+        this.button.setValue(v);
+    }
+});
+BI.Copy2GroupBar.EVENT_CHANGE = "Copy2GroupBar.EVENT_CHANGE";
+BI.Copy2GroupBar.EVENT_START = "Copy2GroupBar.EVENT_START";
+BI.Copy2GroupBar.EVENT_EMPTY = "Copy2GroupBar.EVENT_EMPTY";
+BI.Copy2GroupBar.EVENT_CLICK_BUTTON = "Copy2GroupBar.EVENT_CLICK_BUTTON";
+$.shortcut("bi.copy2group_bar", BI.Copy2GroupBar);
\ No newline at end of file
diff --git a/src/widget/date/calendar/combo.month.date.js b/src/widget/date/calendar/combo.month.date.js
new file mode 100644
index 000000000..84aefdba3
--- /dev/null
+++ b/src/widget/date/calendar/combo.month.date.js
@@ -0,0 +1,61 @@
+/**
+ * 日期控件中的月份下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.MonthDateCombo
+ * @extends BI.Trigger
+ */
+BI.MonthDateCombo = BI.inherit(BI.Trigger, {
+    _defaultConfig: function() {
+        return BI.extend( BI.MonthDateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-combo",
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.MonthDateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_triangle_trigger"
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.month_popup"
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){
+            self.setValue(self.popup.getValue());
+        })
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            offsetStyle: "center",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        })
+        this.combo.on(BI.Combo.EVENT_CHANGE, function(){
+            self.combo.hideView();
+            self.fireEvent(BI.MonthDateCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function(v){
+        this.trigger.setValue(v + 1);
+        this.popup.setValue(v);
+    },
+
+    getValue: function(){
+        return this.popup.getValue();
+    }
+});
+BI.MonthDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.month_date_combo', BI.MonthDateCombo);
\ No newline at end of file
diff --git a/src/widget/date/calendar/combo.year.date.js b/src/widget/date/calendar/combo.year.date.js
new file mode 100644
index 000000000..766c23916
--- /dev/null
+++ b/src/widget/date/calendar/combo.year.date.js
@@ -0,0 +1,66 @@
+/**
+ * 年份下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.YearDateCombo
+ * @extends BI.Trigger
+ */
+BI.YearDateCombo = BI.inherit(BI.Trigger, {
+    _defaultConfig: function() {
+        return BI.extend( BI.YearDateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-combo",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.YearDateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_triangle_trigger"
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.year_popup",
+            min: o.min,
+            max: o.max
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.YearDateCombo.EVENT_CHANGE);
+        })
+
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            offsetStyle: "center",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        })
+        this.combo.on(BI.Combo.EVENT_CHANGE, function(){
+            self.fireEvent(BI.YearDateCombo.EVENT_CHANGE);
+        })
+    },
+
+    setValue: function(v){
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function(){
+        return this.popup.getValue();
+    }
+});
+BI.YearDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_date_combo', BI.YearDateCombo);
\ No newline at end of file
diff --git a/src/widget/date/calendar/picker.date.js b/src/widget/date/calendar/picker.date.js
new file mode 100644
index 000000000..69ca50b06
--- /dev/null
+++ b/src/widget/date/calendar/picker.date.js
@@ -0,0 +1,127 @@
+/**
+ * Created by GUY on 2015/9/7.
+ * @class BI.DatePicker
+ * @extends BI.Widget
+ */
+BI.DatePicker = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DatePicker.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-picker",
+            height: 25,
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31' //最大日期
+        })
+    },
+
+    _init: function () {
+        BI.DatePicker.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this._year = new Date().getFullYear();
+        this._month = new Date().getMonth();
+        this.left = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-h-font",
+            width: 25,
+            height: 25
+        });
+        this.left.on(BI.IconButton.EVENT_CHANGE, function () {
+            if (self._month === 0) {
+                self.setValue({
+                    year: self.year.getValue() - 1,
+                    month: 11
+                })
+            } else {
+                self.setValue({
+                    year: self.year.getValue(),
+                    month: self.month.getValue() - 1
+                })
+            }
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        this.right = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-h-font",
+            width: 25,
+            height: 25
+        });
+
+        this.right.on(BI.IconButton.EVENT_CHANGE, function () {
+            if (self._month === 11) {
+                self.setValue({
+                    year: self.year.getValue() + 1,
+                    month: 0
+                })
+            } else {
+                self.setValue({
+                    year: self.year.getValue(),
+                    month: self.month.getValue() + 1
+                })
+            }
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        this.year = BI.createWidget({
+            type: "bi.year_date_combo",
+            min: o.min,
+            max: o.max
+        });
+        this.year.on(BI.YearDateCombo.EVENT_CHANGE, function () {
+            self.setValue({
+                year: self.year.getValue(),
+                month: self.month.getValue()
+            });
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        })
+        this.month = BI.createWidget({
+            type: "bi.month_date_combo"
+        });
+        this.month.on(BI.MonthDateCombo.EVENT_CHANGE, function () {
+            self.setValue({
+                year: self.year.getValue(),
+                month: self.month.getValue()
+            });
+            self.fireEvent(BI.DatePicker.EVENT_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.left,
+                width: 25
+            }, {
+                type: "bi.center_adapt",
+                items: [{
+                    type: "bi.horizontal",
+                    width: 100,
+                    items: [this.year, this.month]
+                }]
+            }, {
+                el: this.right,
+                width: 25
+            }]
+        })
+        this.setValue({
+            year: this._year,
+            month: this._month
+        })
+    },
+
+    setValue: function (ob) {
+        this._year = ob.year;
+        this._month = ob.month;
+        this.year.setValue(ob.year);
+        this.month.setValue(ob.month);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            month: this.month.getValue()
+        }
+    }
+});
+BI.DatePicker.EVENT_CHANGE = "EVENT_CHANGE"
+$.shortcut("bi.date_picker", BI.DatePicker);
\ No newline at end of file
diff --git a/src/widget/date/calendar/popup.calendar.date.js b/src/widget/date/calendar/popup.calendar.date.js
new file mode 100644
index 000000000..a1d136c58
--- /dev/null
+++ b/src/widget/date/calendar/popup.calendar.date.js
@@ -0,0 +1,96 @@
+/**
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateCalendarPopup
+ * @extends BI.Widget
+ */
+BI.DateCalendarPopup = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DateCalendarPopup.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-calendar-popup",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            selectedTime: null
+        })
+    },
+
+    _createNav: function (v) {
+        var date = BI.Calendar.getDateJSONByPage(v);
+        var calendar = BI.createWidget({
+            type: "bi.calendar",
+            logic: {
+                dynamic: true
+            },
+            min: this.options.min,
+            max: this.options.max,
+            year: date.year,
+            month: date.month,
+            day: this.selectedTime.day
+        });
+        return calendar;
+    },
+
+    _init: function () {
+        BI.DateCalendarPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.today = new Date();
+        this._year = this.today.getFullYear();
+        this._month = this.today.getMonth();
+        this._day = this.today.getDate();
+
+        this.selectedTime = o.selectedTime || {
+                year: this._year,
+                month: this._month,
+                day: this._day
+            };
+        this.datePicker = BI.createWidget({
+            type: "bi.date_picker",
+            min: o.min,
+            max: o.max
+        });
+
+        this.calendar = BI.createWidget({
+            direction: "top",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            type: "bi.navigation",
+            tab: this.datePicker,
+            cardCreator: BI.bind(this._createNav, this),
+
+            afterCardCreated: function () {
+
+            },
+
+            afterCardShow: function () {
+                this.setValue(self.selectedTime);
+            }
+        });
+
+        this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () {
+            self.selectedTime = self.datePicker.getValue();
+            self.selectedTime.day = 1;
+            self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime));
+        });
+
+        this.calendar.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedTime = self.calendar.getValue();
+            self.setValue(self.selectedTime);
+            self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (timeOb) {
+        this.datePicker.setValue(timeOb);
+        this.calendar.setSelect(BI.Calendar.getPageByDateJSON(timeOb));
+        this.calendar.setValue(timeOb);
+        this.selectedTime = timeOb;
+    },
+
+    getValue: function () {
+        return this.selectedTime;
+    }
+});
+BI.DateCalendarPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.date_calendar_popup", BI.DateCalendarPopup);
\ No newline at end of file
diff --git a/src/widget/date/calendar/trigger.triangle.date.js b/src/widget/date/calendar/trigger.triangle.date.js
new file mode 100644
index 000000000..9649f1871
--- /dev/null
+++ b/src/widget/date/calendar/trigger.triangle.date.js
@@ -0,0 +1,70 @@
+/**
+ * 日期控件中的年份或月份trigger
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateTriangleTrigger
+ * @extends BI.Trigger
+ */
+BI.DateTriangleTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        height: 25,
+        iconWidth: 16,
+        iconHeight: 13
+    },
+
+    _defaultConfig: function() {
+        return BI.extend( BI.DateTriangleTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-triangle-trigger pull-down-ha-font cursor-pointer",
+            height: 25
+        });
+    },
+    _init: function() {
+        BI.DateTriangleTrigger.superclass._init.apply(this, arguments);
+        var o = this.options, c = this._const;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-item-text",
+            textAlign: "right",
+            text: o.text,
+            value: o.value,
+            height: c.height
+        })
+        this.icon = BI.createWidget({
+            type: "bi.icon",
+            width: c.iconWidth,
+            height: c.iconHeight
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                width: 50,
+                height: c.height,
+                items: [this.text, this.icon]
+            }]
+        })
+    },
+
+    setValue: function(v){
+        this.text.setValue(v);
+    },
+
+    getValue: function(){
+        return this.text.getValue();
+    },
+
+    setText: function(v){
+        this.text.setText(v);
+    },
+
+    getText: function(){
+        return this.item.getText();
+    },
+
+    getKey: function(){
+
+    }
+});
+$.shortcut('bi.date_triangle_trigger', BI.DateTriangleTrigger);
\ No newline at end of file
diff --git a/src/widget/date/combo.date.js b/src/widget/date/combo.date.js
new file mode 100644
index 000000000..9081ee53b
--- /dev/null
+++ b/src/widget/date/combo.date.js
@@ -0,0 +1,59 @@
+/**
+ * 日期下拉框
+ *
+ * Created by GUY on 2015/9/7.
+ * @class BI.DateCombo
+ * @extends BI.Widget
+ */
+BI.DateCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-combo",
+            height: 30
+        });
+    },
+    _init: function () {
+        BI.DateCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.date_trigger"
+        });
+
+        this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function () {
+            self.combo.toggle();
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.date_calendar_popup"
+        });
+
+        this.popup.on(BI.DateCalendarPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                width: 270,
+                el: this.popup,
+                stopPropagation: false
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+$.shortcut('bi.date_combo', BI.DateCombo);
\ No newline at end of file
diff --git a/src/widget/date/trigger.date.js b/src/widget/date/trigger.date.js
new file mode 100644
index 000000000..030833ae6
--- /dev/null
+++ b/src/widget/date/trigger.date.js
@@ -0,0 +1,269 @@
+BI.DateTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 30,
+        watermark: BI.i18nText("BI-Unrestricted"),
+        yearLength: 4,
+        yearMonthLength: 7
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-date-trigger",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.DateTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                var date = v.match(/\d+/g);
+                self._autoAppend(v, date);
+                return self._dateCheck(v) && Date.checkLegal(v) && self._checkVoid({
+                        year: date[0],
+                        month: date[1],
+                        day: date[2]
+                    });
+            },
+            quitChecker: function () {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            watermark: c.watermark,
+            errorText: function () {
+                if (self.editor.isEditing()) {
+                    return BI.i18nText("BI-Date_Trigger_Error_Text");
+                }
+                return BI.i18nText("BI-Year_Trigger_Invalid_Text");
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_KEY_DOWN)
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_VALID, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_VALID);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_ERROR);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setState(value);
+            }
+
+            if (BI.isNotEmptyString(value)) {
+                var date = value.split("-");
+                self.store_value = {
+                    type: BICst.MULTI_DATE_CALENDAR,
+                    value:{
+                        year: date[0] | 0,
+                        month: date[1] - 1,
+                        day: date[2] | 0
+                    }
+                };
+            }
+            self.fireEvent(BI.DateTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DateTrigger.EVENT_CHANGE);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: BI.createWidget(),
+                width: 30
+            }, {
+                el: this.editor
+            }]
+        })
+    },
+    _dateCheck: function (date) {
+        return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date;
+    },
+    _checkVoid: function (obj) {
+        return !Date.checkVoid(obj.year, obj.month, obj.day, this.options.min, this.options.max)[0];
+    },
+    _autoAppend: function (v, dateObj) {
+        var self = this;
+        var date = Date.parseDateTime(v, "%Y-%X-%d").print("%Y-%X-%d");
+        var yearCheck = function (v) {
+            return Date.parseDateTime(v, "%Y").print("%Y") == v && date >= self.options.min && date <= self.options.max;
+        };
+        var monthCheck = function (v) {
+            return Date.parseDateTime(v, "%Y-%X").print("%Y-%X") == v && date >= self.options.min && date <= self.options.max;
+        };
+        if (BI.isNotNull(dateObj) && Date.checkLegal(v)) {
+            switch (v.length) {
+                case this._const.yearLength:
+                    if (yearCheck(v)) {
+                        this.editor.setValue(v + "-");
+                    }
+                    break;
+                case this._const.yearMonthLength:
+                    if (monthCheck(v)) {
+                        this.editor.setValue(v + "-");
+                    }
+                    break;
+            }
+        }
+    },
+
+    setValue: function (v) {
+        var type, value, self = this;
+        var date = new Date();
+        this.store_value = v;
+        if (BI.isNotNull(v)) {
+            type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value;
+            if(BI.isNull(value)){
+                value = v;
+            }
+        }
+        var _setInnerValue = function (date, text) {
+            var dateStr = date.print("%Y-%x-%e");
+            self.editor.setState(dateStr);
+            self.editor.setValue(dateStr);
+            self.setTitle(text + ":" + dateStr);
+        };
+        switch (type) {
+            case BICst.MULTI_DATE_YEAR_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV];
+                date = new Date((date.getFullYear() - 1 * value), date.getMonth(), date.getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER];
+                date = new Date((date.getFullYear() + 1 * value), date.getMonth(), date.getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN];
+                date = new Date(date.getFullYear(), 0, 1);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_YEAR_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END];
+                date = new Date(date.getFullYear(), 11, 31);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV];
+                date = new Date().getBeforeMulQuarter(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER];
+                date = new Date().getAfterMulQuarter(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN];
+                date = new Date().getQuarterStartDate();
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_QUARTER_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END];
+                date = new Date().getQuarterEndDate();
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV];
+                date = new Date().getBeforeMultiMonth(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER];
+                date = new Date().getAfterMultiMonth(value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_BEGIN:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN];
+                date = new Date(date.getFullYear(), date.getMonth(), 1);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_MONTH_END:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END];
+                date = new Date(date.getFullYear(), date.getMonth(), (date.getLastDateOfMonth()).getDate());
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_WEEK_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV];
+                date = date.getOffsetDate(-7 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_WEEK_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER];
+                date = date.getOffsetDate(7 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_PREV:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV];
+                date = date.getOffsetDate(-1 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_AFTER:
+                var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER];
+                date = date.getOffsetDate(1 * value);
+                _setInnerValue(date, text);
+                break;
+            case BICst.MULTI_DATE_DAY_TODAY:
+                var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY];
+                date = new Date();
+                _setInnerValue(date, text);
+                break;
+            default:
+                if (BI.isNull(value) || BI.isNull(value.day)) {
+                    this.editor.setState("");
+                    this.editor.setValue("");
+                    this.setTitle("");
+                } else {
+                    var dateStr = value.year + "-" + (value.month + 1) + "-" + value.day;
+                    this.editor.setState(dateStr);
+                    this.editor.setValue(dateStr);
+                    this.setTitle(dateStr);
+                }
+                break;
+        }
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+    getValue: function () {
+        return this.store_value;
+    }
+
+});
+BI.DateTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.DateTrigger.EVENT_START = "EVENT_START";
+BI.DateTrigger.EVENT_STOP = "EVENT_STOP";
+BI.DateTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.DateTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DateTrigger.EVENT_VALID = "EVENT_VALID";
+BI.DateTrigger.EVENT_ERROR = "EVENT_ERROR";
+BI.DateTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK";
+BI.DateTrigger.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
+$.shortcut("bi.date_trigger", BI.DateTrigger);
\ No newline at end of file
diff --git a/src/widget/datepane/datepanenotselectday.js b/src/widget/datepane/datepanenotselectday.js
new file mode 100644
index 000000000..0b7e674ad
--- /dev/null
+++ b/src/widget/datepane/datepanenotselectday.js
@@ -0,0 +1,122 @@
+/**
+ * Created by zcf on 2017/2/20.
+ */
+BI.DatePaneWidget = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        var conf = BI.DatePaneWidget.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-date-pane-widget",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            selectedTime: null
+        })
+    },
+    _init: function () {
+        BI.DatePaneWidget.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.today = new Date();
+        this._year = this.today.getFullYear();
+        this._month = this.today.getMonth();
+
+        this.selectedTime = o.selectedTime || {
+                year: this._year,
+                month: this._month
+            };
+
+        this.datePicker = BI.createWidget({
+            type: "bi.date_picker",
+            min: o.min,
+            max: o.max
+        });
+        this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () {
+            self.selectedTime = self.datePicker.getValue();
+            // self.selectedTime.day = 1;
+            self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime));
+        });
+
+        this.calendar = BI.createWidget({
+            direction: "top",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            type: "bi.navigation",
+            tab: this.datePicker,
+            cardCreator: BI.bind(this._createNav, this)
+
+            // afterCardCreated: function () {
+            //
+            // },
+            //
+            // afterCardShow: function () {
+            //     // this.setValue(self.selectedTime);
+            // }
+        });
+        this.calendar.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedTime = self.calendar.getValue();
+            self.calendar.empty();
+            self.setValue(self.selectedTime);
+            self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE);
+        });
+
+    },
+
+    _createNav: function (v) {
+        var date = BI.Calendar.getDateJSONByPage(v);
+        var calendar = BI.createWidget({
+            type: "bi.calendar",
+            logic: {
+                dynamic: true
+            },
+            min: this.options.min,
+            max: this.options.max,
+            year: date.year,
+            month: date.month,
+            day: this.selectedTime.day
+        });
+        return calendar;
+    },
+
+    _getNewCurrentDate: function () {
+        var today = new Date();
+        return {
+            year: today.getFullYear(),
+            month: today.getMonth()
+        }
+    },
+
+    _setCalenderValue: function (date) {
+        this.calendar.setSelect(BI.Calendar.getPageByDateJSON(date));
+        this.calendar.setValue(date);
+        this.selectedTime = date;
+    },
+
+    _setDatePicker: function (timeOb) {
+        if (BI.isNull(timeOb) || BI.isNull(timeOb.year) || BI.isNull(timeOb.month)) {
+            this.datePicker.setValue(this._getNewCurrentDate());
+        } else {
+            this.datePicker.setValue(timeOb);
+        }
+    },
+
+    _setCalendar: function (timeOb) {
+        if (BI.isNull(timeOb) || BI.isNull(timeOb.day)) {
+            this.calendar.empty();
+            this._setCalenderValue(this._getNewCurrentDate());
+        } else {
+            this._setCalenderValue(timeOb)
+        }
+    },
+
+    setValue: function (timeOb) {
+        this._setDatePicker(timeOb);
+        this._setCalendar(timeOb);
+    },
+
+    getValue: function () {
+        return this.selectedTime;
+    }
+
+});
+$.shortcut("bi.date_pane_widget", BI.DatePaneWidget);
\ No newline at end of file
diff --git a/src/widget/directionpathchooser/directionpathchooser.js b/src/widget/directionpathchooser/directionpathchooser.js
new file mode 100644
index 000000000..ae3e8d794
--- /dev/null
+++ b/src/widget/directionpathchooser/directionpathchooser.js
@@ -0,0 +1,243 @@
+/**
+ * 带有方向的pathchooser
+ *
+ * Created by GUY on 2016/4/21.
+ * @class BI.DirectionPathChooser
+ * @extends BI.Widget
+ */
+BI.DirectionPathChooser = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#808080",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DirectionPathChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.DirectionPathChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.pathChooser = BI.createWidget({
+            type: "bi.path_chooser",
+            element: this,
+            items: o.items
+        });
+        this.pathChooser.on(BI.PathChooser.EVENT_CHANGE, function (start, index) {
+            //self._unselectAllArrows();
+            self._setValue(start, index);
+            self.fireEvent(BI.DirectionPathChooser.EVENT_CHANGE);
+        });
+        this._drawArrows();
+
+    },
+
+    _unselectAllArrows: function () {
+        var self = this, lineColor = this._const.lineColor;
+        BI.each(this.arrows, function (region, rs) {
+            BI.each(rs, function (idx, arrows) {
+                BI.each(arrows, function (i, arrow) {
+                    arrow.attr({fill: lineColor, stroke: lineColor});
+                });
+            });
+        });
+    },
+
+    _drawOneArrow: function (dot, direction) {
+        //0,1,2,3  上右下左
+        var lineColor = this._const.lineColor;
+        var selectLineColor = this._const.selectLineColor;
+        var svg = this.pathChooser.svg;
+        var path = "";
+        switch (direction) {
+            case 0:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 3) + "," + (dot.y + 5)
+                    + "L" + (dot.x + 3) + "," + (dot.y + 5)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 1:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 5) + "," + (dot.y - 3)
+                    + "L" + (dot.x - 5) + "," + (dot.y + 3)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 2:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x - 3) + "," + (dot.y - 5)
+                    + "L" + (dot.x + 3) + "," + (dot.y - 5)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+            case 3:
+                path = "M" + dot.x + "," + dot.y
+                    + "L" + (dot.x + 5) + "," + (dot.y - 3)
+                    + "L" + (dot.x + 5) + "," + (dot.y + 3)
+                    + "L" + dot.x + "," + dot.y;
+                break;
+        }
+        return svg.path(path).attr({fill: lineColor, stroke: lineColor});
+    },
+
+    _drawArrows: function () {
+        var self = this, o = this.options;
+        var routes = this.pathChooser.routes;
+        var pathes = this.pathChooser.pathes;
+        var store = this.pathChooser.store;
+        this.arrows = {};
+        BI.each(routes, function (region, ps) {
+            self.arrows[region] = [];
+            BI.each(ps, function (idx, path) {
+                self.arrows[region][idx] = [];
+                var dots = pathes[region][idx];
+                BI.each(dots, function (i, dot) {
+                    if (i > 0 && i < dots.length - 1) {
+                        var arrow;
+                        if (dot.y === dots[i - 1].y) {
+                            if (dots[i + 1].y != dot.y) {
+                                if (store[path[path.length - 2]].direction === -1) {
+                                    if (i - 1 > 0) {
+                                        arrow = self._drawOneArrow(dots[i - 1], 3);
+                                    }
+                                } else {
+                                    arrow = self._drawOneArrow(dots[i], 1);
+                                }
+                            }
+                        } else if (dot.x === dots[i - 1].x) {
+                            if (dot.y > dots[i - 1].y) {
+                                if (store[BI.first(path)].direction === -1) {
+                                    arrow = self._drawOneArrow(dots[i - 1], 0);
+                                } else {
+                                    arrow = self._drawOneArrow(dot, 2);
+                                }
+                            } else {
+                                if (store[path[path.length - 2]].direction === -1) {
+                                    arrow = self._drawOneArrow(dots[i - 1], 2);
+                                } else {
+                                    arrow = self._drawOneArrow(dot, 0);
+                                }
+                            }
+                        }
+                        if (arrow) {
+                            self.arrows[region][idx].push(arrow);
+                        }
+                    }
+                });
+                BI.each(path, function (i, node) {
+                    if (i !== 0) {
+                        var arrow;
+                        var from = path[i - 1];
+                        if (store[from].direction === -1) {
+                            var regionIndex = self.pathChooser.getRegionIndexById(from);
+                            var x = getXoffsetByRegionIndex(regionIndex, -1);
+                            var y = getYByXoffset(dots, x);
+                            arrow = self._drawOneArrow({x: x, y: y}, 3);
+                        } else {
+                            var regionIndex = self.pathChooser.getRegionIndexById(node);
+                            var x = getXoffsetByRegionIndex(regionIndex);
+                            var y = getYByXoffset(dots, x);
+                            arrow = self._drawOneArrow({x: x, y: y}, 1);
+                        }
+                        if (arrow) {
+                            self.arrows[region][idx].push(arrow);
+                        }
+                    }
+                });
+            })
+        });
+
+        function getXoffsetByRegionIndex(regionIndex, diregion) {
+            if (diregion === -1) {
+                return 100 * (regionIndex + 1) - 20;
+            }
+            return 100 * regionIndex + 20;
+        }
+
+        function getYByXoffset(dots, xoffset) {
+            var finded = BI.find(dots, function (i, dot) {
+                if (i > 0) {
+                    if (dots[i - 1].x < xoffset && dots[i].x > xoffset) {
+                        return true;
+                    }
+                }
+            });
+            return finded.y;
+        }
+    },
+
+    _setValue: function (start, index) {
+        var self = this;
+        var lineColor = this._const.lineColor;
+        var selectLineColor = this._const.selectLineColor;
+        var routes = this.pathChooser.routes;
+        var starts = this.pathChooser.start;
+        var each = [start];
+        if (starts.contains(start)) {
+            each = starts;
+        }
+        BI.each(each, function (i, s) {
+            BI.each(self.arrows[s], function (j, arrows) {
+                BI.each(arrows, function (k, arrow) {
+                    arrow.attr({fill: lineColor, stroke: lineColor}).toFront();
+                });
+            });
+        });
+        BI.each(this.arrows[start][index], function (i, arrow) {
+            arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront();
+        });
+        var current = BI.last(routes[start][index]);
+        while (current && routes[current] && routes[current].length === 1) {
+            BI.each(self.arrows[current][0], function (i, arrow) {
+                arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront();
+            });
+            current = BI.last(routes[current][0]);
+        }
+    },
+
+    setValue: function (v) {
+        this.pathChooser.setValue(v);
+        this._unselectAllArrows();
+        var routes = this.pathChooser.routes;
+        var nodes = BI.keys(routes), self = this;
+        var result = [], array = [];
+        BI.each(v, function (i, val) {
+            if (BI.contains(nodes, val)) {
+                if (array.length > 0) {
+                    array.push(val);
+                    result.push(array);
+                    array = [];
+                }
+            }
+            array.push(val);
+        });
+        if (array.length > 0) {
+            result.push(array);
+        }
+        //画这n条路径
+        BI.each(result, function (idx, path) {
+            var start = path[0];
+            var index = BI.findIndex(routes[start], function (idx, p) {
+                if (BI.isEqual(path, p)) {
+                    return true;
+                }
+            });
+            if (index >= 0) {
+                self._setValue(start, index);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.pathChooser.getValue();
+    },
+
+    populate: function (items) {
+        this.pathChooser.populate(items);
+        this._drawArrows();
+    }
+});
+BI.DirectionPathChooser.EVENT_CHANGE = "DirectionPathChooser.EVENT_CHANGE";
+$.shortcut('bi.direction_path_chooser', BI.DirectionPathChooser);
\ No newline at end of file
diff --git a/src/widget/downlist/combo.downlist.js b/src/widget/downlist/combo.downlist.js
new file mode 100644
index 000000000..35de76a33
--- /dev/null
+++ b/src/widget/downlist/combo.downlist.js
@@ -0,0 +1,74 @@
+/**
+ * Created by roy on 15/8/14.
+ */
+BI.DownListCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-combo",
+            invalid: false,
+            height: 25,
+            items: [],
+            adjustLength: 0,
+            el: {}
+        })
+    },
+
+    _init: function () {
+        BI.DownListCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.popupview = BI.createWidget({
+            type: "bi.down_list_popup",
+            items: o.items,
+            chooseType: o.chooseType
+        });
+
+        this.popupview.on(BI.DownListPopup.EVENT_CHANGE, function (value) {
+            self.fireEvent(BI.DownListCombo.EVENT_CHANGE, value);
+            self.downlistcombo.hideView();
+        });
+
+        this.popupview.on(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, function (value, fatherValue) {
+            self.fireEvent(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, value, fatherValue);
+            self.downlistcombo.hideView();
+        });
+
+
+        this.downlistcombo = BI.createWidget({
+            element: this,
+            type: 'bi.combo',
+            isNeedAdjustWidth: false,
+            adjustLength: o.adjustLength,
+            el: BI.createWidget(o.el, {
+                type: "bi.icon_trigger",
+                extraCls: o.iconCls ? o.iconCls : "pull-down-font",
+                width: o.width,
+                height: o.height
+            }),
+            popup: {
+                el: this.popupview,
+                stopPropagation: true,
+                maxHeight: 400
+            }
+        });
+
+        this.downlistcombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.DownListCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+    },
+
+    populate: function (items) {
+        this.popupview.populate(items);
+    },
+
+    setValue: function (v) {
+        this.popupview.setValue(v);
+    },
+    getValue: function () {
+        return this.popupview.getValue()
+    }
+});
+BI.DownListCombo.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DownListCombo.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE";
+BI.DownListCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+
+$.shortcut("bi.down_list_combo", BI.DownListCombo);
\ No newline at end of file
diff --git a/src/widget/downlist/group.downlist.js b/src/widget/downlist/group.downlist.js
new file mode 100644
index 000000000..5cf1da084
--- /dev/null
+++ b/src/widget/downlist/group.downlist.js
@@ -0,0 +1,50 @@
+/**
+ * Created by roy on 15/9/6.
+ */
+BI.DownListGroup = BI.inherit(BI.Widget, {
+    constants: {
+        iconCls: "check-mark-ha-font"
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.DownListGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-down-list-group",
+            items: [
+                {
+                    el: {}
+                }
+            ]
+        })
+    },
+    _init: function () {
+        BI.DownListGroup.superclass._init.apply(this, arguments);
+        var o = this.options, self = this;
+
+        this.downlistgroup = BI.createWidget({
+            element: this,
+            type: "bi.button_tree",
+            items: o.items,
+            chooseType: 0,//0单选,1多选
+            layouts: [{
+                type: "bi.vertical",
+                hgap: 0,
+                vgap: 0
+            }]
+        });
+        this.downlistgroup.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if(type === BI.Events.CLICK) {
+                self.fireEvent(BI.DownListGroup.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+    getValue:function(){
+        return this.downlistgroup.getValue();
+    },
+    setValue:function(v){
+        this.downlistgroup.setValue(v);
+    }
+
+
+})
+BI.DownListGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_group", BI.DownListGroup);
\ No newline at end of file
diff --git a/src/widget/downlist/item.downlist.js b/src/widget/downlist/item.downlist.js
new file mode 100644
index 000000000..2ad9e4148
--- /dev/null
+++ b/src/widget/downlist/item.downlist.js
@@ -0,0 +1,79 @@
+BI.DownListItem = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.DownListItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-down-list-item",
+            cls: "",
+            height: 25,
+            logic: {
+                dynamic: true
+            },
+            selected: false,
+            iconHeight: null,
+            iconWidth: null,
+            textHgap: 0,
+            textVgap: 0,
+            textLgap: 0,
+            textRgap: 0
+        })
+    },
+    _init: function () {
+        BI.DownListItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.icon_text_item",
+            element: this,
+            height: o.height,
+            text: o.text,
+            value: o.value,
+            logic: o.logic,
+            selected: o.selected,
+            disabled: o.disabled,
+            iconHeight: o.iconHeight,
+            iconWidth: o.iconWidth,
+            textHgap: o.textHgap,
+            textVgap: o.textVgap,
+            textLgap: o.textLgap,
+            textRgap: o.textRgap,
+            father: o.father
+        });
+        this.text.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.text.on(BI.IconTextItem.EVENT_CHANGE, function () {
+            self.fireEvent(BI.DownListItem.EVENT_CHANGE);
+        });
+        // this.setSelected(o.selected);
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    isSelected: function () {
+        return this.text.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.text.setSelected(b);
+        // if (b === true) {
+        //     this.element.addClass("dot-e-font");
+        // } else {
+        //     this.element.removeClass("dot-e-font");
+        // }
+    },
+
+    setValue: function (v) {
+        this.text.setValue(v);
+    },
+
+    getValue: function () {
+        return this.text.getValue();
+    }
+});
+BI.DownListItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_item", BI.DownListItem);
\ No newline at end of file
diff --git a/src/widget/downlist/item.downlistgroup.js b/src/widget/downlist/item.downlistgroup.js
new file mode 100644
index 000000000..b363e5835
--- /dev/null
+++ b/src/widget/downlist/item.downlistgroup.js
@@ -0,0 +1,123 @@
+BI.DownListGroupItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        var conf = BI.DownListGroupItem.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-down-list-group-item",
+            logic: {
+                dynamic: false
+            },
+            invalid: true,
+            iconCls1: "dot-e-font",
+            iconCls2: "pull-right-e-font"
+        })
+    },
+    _init: function () {
+        BI.DownListGroupItem.superclass._init.apply(this, arguments);
+        var o = this.options;
+        var self = this;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            cls: "list-group-item-text",
+            textAlign: "left",
+            text: o.text,
+            value: o.value,
+            height: o.height
+        })
+
+        this.icon1 = BI.createWidget({
+            type: "bi.icon_button",
+            cls: o.iconCls1,
+            width: 25,
+            forceNotSelected: true
+        })
+
+        this.icon2 = BI.createWidget({
+            type: "bi.icon_button",
+            cls: o.iconCls2,
+            width: 25,
+            forceNotSelected: true
+        })
+
+        var blank = BI.createWidget({
+            type: "bi.layout",
+            width: 25
+        })
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.icon2,
+                top: 0,
+                bottom: 0,
+                right: 0
+            }]
+        })
+
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
+            items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon1, this.text, blank)
+        }))));
+
+        this.element.on("mouseenter." + this.getName(), function (e) {
+            if (self.element.__isMouseInBounds__(e) && self.isEnabled()) {
+                self.hover();
+            } else {
+                self.dishover();
+            }
+        });
+        this.element.on("mousemove." + this.getName(), function (e) {
+            if (!self.element.__isMouseInBounds__(e) && self.isEnabled()) {
+                self.dishover()
+            }
+        });
+        this.element.on("mouseleave." + this.getName(), function () {
+            if (self.isEnabled()) {
+                self.dishover()
+            }
+        });
+    },
+
+    hover: function () {
+        BI.DownListGroupItem.superclass.hover.apply(this, arguments);
+        this.icon1.element.addClass("hover");
+        this.icon2.element.addClass("hover");
+
+    },
+
+    dishover: function () {
+        BI.DownListGroupItem.superclass.dishover.apply(this, arguments);
+        this.icon1.element.removeClass("hover");
+        this.icon2.element.removeClass("hover");
+    },
+
+    doClick: function () {
+        BI.DownListGroupItem.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.DownListGroupItem.EVENT_CHANGE, this.getValue());
+        }
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    setValue: function (v) {
+        var self = this, o = this.options;
+        v = BI.isArray(v) ? v : [v];
+        BI.find(v, function(idx, value){
+            if(BI.contains(o.childValues, value)){
+                self.icon1.setSelected(true);
+                return true;
+            }else{
+                self.icon1.setSelected(false);
+            }
+        })
+    }
+});
+BI.DownListGroupItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.down_list_group_item", BI.DownListGroupItem);
\ No newline at end of file
diff --git a/src/widget/downlist/popup.downlist.js b/src/widget/downlist/popup.downlist.js
new file mode 100644
index 000000000..e003d649d
--- /dev/null
+++ b/src/widget/downlist/popup.downlist.js
@@ -0,0 +1,232 @@
+/**
+ * Created by roy on 15/9/8.
+ * 处理popup中的item分组样式
+ * 一个item分组中的成员大于一时,该分组设置为单选,并且默认状态第一个成员设置为已选择项
+ */
+BI.DownListPopup = BI.inherit(BI.Pane, {
+    constants: {
+        nextIcon: "pull-right-e-font",
+        height: 25,
+        iconHeight: 12,
+        iconWidth: 12,
+        hgap: 0,
+        vgap: 0,
+        border: 1
+    },
+    _defaultConfig: function () {
+        var conf = BI.DownListPopup.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-down-list-popup",
+            items: [],
+            chooseType: BI.Selection.Multi
+        })
+    },
+    _init: function () {
+        BI.DownListPopup.superclass._init.apply(this, arguments);
+        this.singleValues = [];
+        this.childValueMap = {};
+        this.fatherValueMap = {};
+        var self = this, o = this.options, children = this._createChildren(o.items);
+        this.popup = BI.createWidget({
+            type: "bi.button_tree",
+            items: BI.createItems(children,
+                {}, {
+                    adjustLength: -2
+                }
+            ),
+            layouts: [{
+                type: "bi.vertical",
+                hgap: this.constants.hgap,
+                vgap: this.constants.vgap
+            }],
+            chooseType: o.chooseType
+        });
+
+        this.popup.on(BI.ButtonTree.EVENT_CHANGE, function (value, object) {
+            var changedValue = value;
+            if (BI.isNotNull(self.childValueMap[value])) {
+                changedValue = self.childValueMap[value];
+                self.fireEvent(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, changedValue, self.fatherValueMap[value])
+            } else {
+                self.fireEvent(BI.DownListPopup.EVENT_CHANGE, changedValue, object);
+            }
+
+
+            if (!self.singleValues.contains(changedValue)) {
+                var item = self.getValue();
+                var result = [];
+                BI.each(item, function (i, valueObject) {
+                    if (valueObject.value != changedValue) {
+                        result.push(valueObject);
+                    }
+                });
+                self.setValue(result);
+            }
+
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.popup]
+        });
+
+    },
+    _createChildren: function (items) {
+        var self = this, result = [];
+        BI.each(items, function (i, it) {
+            var item_done = {
+                type: "bi.down_list_group",
+                items: []
+            };
+
+            BI.each(it, function (i, item) {
+                if (BI.isNotEmptyArray(item.children) && !BI.isEmpty(item.el)) {
+                    item.type = "bi.combo_group";
+                    item.cls = "down-list-group";
+                    item.trigger = "hover";
+                    item.isNeedAdjustWidth = false;
+                    item.el.title = item.el.title || item.el.text;
+                    item.el.type = "bi.down_list_group_item";
+                    item.el.logic = {
+                        dynamic: true
+                    };
+                    item.el.height = self.constants.height;
+                    item.el.iconCls2 = self.constants.nextIcon;
+                    item.popup = {
+                        lgap: 4,
+                        el: {
+                            type: "bi.button_tree",
+                            chooseType: 0,
+                            layouts: [{
+                                type: "bi.vertical"
+                            }]
+
+                        }
+                    };
+                    item.el.childValues = [];
+                    BI.each(item.children, function (i, child) {
+                        var fatherValue = BI.deepClone(item.el.value);
+                        var childValue = BI.deepClone(child.value);
+                        self.singleValues.push(child.value);
+                        child.type = "bi.down_list_item";
+                        child.extraCls = " child-down-list-item";
+                        child.title = child.title || child.text;
+                        child.textRgap = 10;
+                        child.isNeedAdjustWidth = false;
+                        child.logic = {
+                            dynamic: true
+                        };
+                        child.father = fatherValue;
+                        self.fatherValueMap[self._createChildValue(fatherValue, childValue)] = fatherValue;
+                        self.childValueMap[self._createChildValue(fatherValue, childValue)] = childValue;
+                        child.value = self._createChildValue(fatherValue, childValue);
+                        item.el.childValues.push(child.value);
+                    })
+                } else {
+                    item.type = "bi.down_list_item";
+                    item.title = item.title || item.text;
+                    item.textRgap = 10;
+                    item.isNeedAdjustWidth = false;
+                    item.logic = {
+                        dynamic: true
+                    }
+                }
+                var el_done = {};
+                el_done.el = item;
+                item_done.items.push(el_done);
+            });
+            if (self._isGroup(item_done.items)) {
+                BI.each(item_done.items, function (i, item) {
+                    self.singleValues.push(item.el.value);
+                })
+            }
+
+            result.push(item_done);
+            if (self._needSpliter(i, items.length)) {
+                var spliter_container = BI.createWidget({
+                    type: "bi.vertical",
+                    items: [{
+                        el: {
+                            type: "bi.layout",
+                            cls: "bi-down-list-spliter cursor-pointer",
+                            height: 0
+                        }
+
+                    }],
+                    cls: "bi-down-list-spliter-container cursor-pointer",
+                    lgap: 10,
+                    rgap: 10
+                });
+                result.push(spliter_container);
+            }
+        });
+        return result;
+    },
+
+    _isGroup: function (i) {
+        return i.length > 1;
+    },
+
+    _needSpliter: function (i, itemLength) {
+        return i < itemLength - 1;
+    },
+
+    _createChildValue: function (fatherValue, childValue) {
+        return fatherValue + "_" + childValue
+    },
+
+    populate: function (items) {
+        BI.DownListPopup.superclass.populate.apply(this, arguments);
+        var self = this;
+        self.childValueMap = {};
+        self.fatherValueMap = {};
+        self.singleValues = [];
+        var children = self._createChildren(items);
+        var popupItem = BI.createItems(children,
+            {}, {
+                adjustLength: -2
+            }
+        );
+        self.popup.populate(popupItem);
+    },
+
+    setValue: function (valueItem) {
+        var self = this;
+        var valueArray = [];
+        BI.each(valueItem, function (i, item) {
+                var value;
+                if (BI.isNotNull(item.childValue)) {
+                    value = self._createChildValue(item.value, item.childValue);
+                } else {
+                    value = item.value;
+                }
+                valueArray.push(value);
+            }
+        );
+        this.popup.setValue(valueArray);
+    },
+
+    getValue: function () {
+        var self = this, result = [];
+        var values = this.popup.getValue();
+        BI.each(values, function (i, value) {
+            var valueItem = {};
+            if (BI.isNotNull(self.childValueMap[value])) {
+                var fartherValue = self.fatherValueMap[value];
+                valueItem.childValue = self.childValueMap[value];
+                valueItem.value = fartherValue;
+            } else {
+                valueItem.value = value;
+            }
+            result.push(valueItem);
+        });
+        return result;
+    }
+
+
+});
+
+BI.DownListPopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.DownListPopup.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE";
+$.shortcut("bi.down_list_popup", BI.DownListPopup);
\ No newline at end of file
diff --git a/src/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.js b/src/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.js
new file mode 100644
index 000000000..eab285f63
--- /dev/null
+++ b/src/widget/dynamicgrouptab/dynamicgroup.tab.buttongroup.js
@@ -0,0 +1,219 @@
+/**
+ * Created by windy on 2016/12/20.
+ */
+BI.DynamicGroupTabButtonGroup = BI.inherit(BI.Widget, {
+
+    _const: {
+        MERGE_ADD_WIDTH: 65
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DynamicGroupTabButtonGroup.superclass._defaultConfig.apply(this, arguments), {
+            cls: "bi-dynamic-group-tab-button-group",
+            items: [],
+            frozenButtons: [],
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DynamicGroupTabButtonGroup.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.tab = BI.createWidget({
+            type: "bi.button_group",
+            height: o.height,
+            items: [],
+            layouts: [{
+                type: "bi.horizontal",
+                scrollable: false,
+                scrollx: false
+            }]
+        });
+
+        this.tab.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.DynamicGroupTabButtonGroup.EVENT_CHANGE, arguments);
+        });
+
+        var self = this;
+
+        this.scrollLeft = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-font bi-icon-button-scroll",
+            invisible: true
+        });
+
+        this.scrollLeft.on(BI.IconButton.EVENT_CHANGE, function () {
+            self._scrollLeft();
+        });
+        this.scrollRight = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-font bi-icon-button-scroll",
+            invisible: true
+        });
+        this.scrollRight.on(BI.IconButton.EVENT_CHANGE, function () {
+            self._scrollRight();
+        });
+        BI.ResizeDetector.addResizeListener(this, function () {
+            self.resize();
+        });
+
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [{
+                type: "bi.horizontal",
+                tgap: -1,
+                height: o.height,
+                scrollx: false,
+                cls: "bi-sheet-tab-dynamic-horizontal",
+                items: [this.tab,
+                    {
+                        type: "bi.vertical_adapt",
+                        items: [this.scrollLeft],
+                        height: o.height
+                    },
+                    {
+                        type: "bi.vertical_adapt",
+                        items: [this.scrollRight],
+                        height: o.height
+                    },
+                    {
+                        type: "bi.vertical_adapt",
+                        items: o.frozenButtons,
+                        height: o.height,
+                        lgap: 10
+                    }
+                ]
+            }]
+        })
+    },
+
+    _scrollLeft: function () {
+        this._scrollTo(this.tab.element[0].scrollLeft - this.scrollSection)
+    },
+
+    _scrollRight: function () {
+        this._scrollTo(this.tab.element[0].scrollLeft + this.scrollSection)
+    },
+
+    _getTotalWidth: function () {
+        var totalWidth = this.element.outerWidth();
+        totalWidth -= this._const.MERGE_ADD_WIDTH;
+        BI.each(this.options.frozenButtons, function (idx, button) {
+            if (BI.isWidget(button)) {
+                totalWidth -= button.getWidth();
+            } else {
+                totalWidth -= button.width;
+            }
+        })
+        return totalWidth;
+    },
+
+    _calculateButtonsWith: function (fn) {
+        var buttonWidth = 0;
+        var self = this;
+        BI.some(this.tab.getAllButtons(), function (idx, item) {
+            buttonWidth += item.element.outerWidth();
+            if (BI.isNotNull(fn) && fn.apply(self, [item])) {
+                return true;
+            }
+        })
+        return buttonWidth;
+    },
+
+    _dealWithScrollButtonState: function () {
+        var buttonWidth = this._calculateButtonsWith();
+        if (this.tab.element[0].scrollLeft === 0) {
+            this.scrollLeft.setEnable(false);
+        } else {
+            this.scrollLeft.setEnable(true);
+        }
+        var ulWidth = this.tab.element.outerWidth();
+        //可以滚动的最大距离
+        var maxLeft = buttonWidth - ulWidth;
+        if (this.tab.element[0].scrollLeft === maxLeft) {
+            this.scrollRight.setEnable(false);
+        } else {
+            this.scrollRight.setEnable(true);
+        }
+    },
+
+    _needScroll: function (visibleWidth, buttonWidth) {
+        var currentLeft = this.tab.element[0].scrollLeft;
+        return (visibleWidth > currentLeft && visibleWidth - currentLeft > buttonWidth) ||
+            (visibleWidth < currentLeft)
+    },
+
+    _scrollTo: function (value) {
+        var self = this;
+        BI.delay(function () {
+            self.tab.element.scrollLeft(value);
+            self._dealWithScrollButtonState();
+        }, 30);
+    },
+
+    _scrollToEnd: function () {
+        this._scrollTo(this._calculateButtonsWith())
+    },
+
+    resize: function () {
+        //获取当前所有可使用的宽度,不包含添加和合并和导航按钮以及之间的空隙
+        var totalWidth = this._getTotalWidth();
+        //所有button的宽度
+        var buttonWidth = this._calculateButtonsWith();
+        var width = buttonWidth;
+        var showScrollButton = false;
+        if (buttonWidth > totalWidth) {
+            width = totalWidth;
+            showScrollButton = true;
+        }
+        this.scrollLeft.setVisible(showScrollButton);
+        this.scrollRight.setVisible(showScrollButton);
+        //这边动态改变buttongroup的宽度,因为最大宽度是变的
+        this.tab.element.width(width);
+        this._dealWithScrollButtonState();
+        this.scrollSection = width * 2 / 3;
+        this.scrollSelectedVisible();
+    },
+
+    scrollSelectedVisible: function () {
+        var value = this.tab.getValue()[0];
+        //从index 0到当前选中的tab的所有button的宽度
+        var visibleWidth = this._calculateButtonsWith(function (item) {
+            if (item.getValue() === value) {
+                return true;
+            }
+        })
+        var buttonWidth = this._getTotalWidth();
+        var scrollWidth = visibleWidth - buttonWidth / 2;
+        if (this._needScroll(visibleWidth, buttonWidth)) {
+            this._scrollTo(scrollWidth)
+        }
+    },
+
+    getAllButtons: function () {
+        return this.tab.getAllButtons.apply(this.tab, arguments);
+    },
+
+    addItems: function (items) {
+        this.tab.addItems.apply(this.tab, arguments);
+        this.resize();
+        this._scrollToEnd();
+    },
+
+    getValue: function () {
+        this.tab.getValue.apply(this.tab, arguments);
+    },
+
+    setValue: function (v) {
+        this.tab.setValue.apply(this.tab, arguments);
+    },
+
+    populate: function () {
+        this.tab.populate.apply(this.tab, arguments);
+        this.resize();
+    }
+})
+
+BI.DynamicGroupTabButtonGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.dynamic_group_tab_button_group", BI.DynamicGroupTabButtonGroup);
\ No newline at end of file
diff --git a/src/widget/exceltable/exceltable.cell.js b/src/widget/exceltable/exceltable.cell.js
new file mode 100644
index 000000000..6b4faf25e
--- /dev/null
+++ b/src/widget/exceltable/exceltable.cell.js
@@ -0,0 +1,31 @@
+/**
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTableCell
+ * @extends BI.Widget
+ */
+BI.ExcelTableCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTableCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.excel_table_cell', BI.ExcelTableCell);
\ No newline at end of file
diff --git a/src/widget/exceltable/exceltable.header.cell.js b/src/widget/exceltable/exceltable.header.cell.js
new file mode 100644
index 000000000..d7d2bbe24
--- /dev/null
+++ b/src/widget/exceltable/exceltable.header.cell.js
@@ -0,0 +1,31 @@
+/**
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTableHeaderCell
+ * @extends BI.Widget
+ */
+BI.ExcelTableHeaderCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTableHeaderCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table-header-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTableHeaderCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: BI.HorizontalAlign.Center,
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.excel_table_header_cell', BI.ExcelTableHeaderCell);
\ No newline at end of file
diff --git a/src/widget/exceltable/exceltable.js b/src/widget/exceltable/exceltable.js
new file mode 100644
index 000000000..d3ceebdaf
--- /dev/null
+++ b/src/widget/exceltable/exceltable.js
@@ -0,0 +1,207 @@
+/**
+ * Excel表格
+ *
+ * Created by GUY on 2016/3/28.
+ * @class BI.ExcelTable
+ * @extends BI.Widget
+ */
+BI.ExcelTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ExcelTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-excel-table",
+            el: {
+                type: "bi.adaptive_table"
+            },
+
+            isNeedResize: false,
+            isResizeAdapt: true,
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: function (row1, row2) { //合并规则, 默认相等时合并
+                return BI.isEqual(row1, row2);
+            },
+
+            columnSize: [],
+            headerRowSize: 37,
+            footerRowSize: 37,
+            rowSize: 37,
+
+            regionColumnSize: false,
+
+            items: [] //二维数组
+        });
+    },
+
+    _init: function () {
+        BI.ExcelTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        var mergeCols = [];
+        BI.each(o.mergeCols, function (i, col) {
+            mergeCols.push(col + 1);
+        });
+        this.table = BI.createWidget(o.el, {
+            type: "bi.table_view",
+            element: this,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+
+            isNeedFreeze: false,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: [""].concat(o.columnSize),
+            headerRowSize: 18,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize || [82, ""]
+        });
+
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+        BI.nextTick(function () {
+            self.setRegionColumnSize(o.regionColumnSize || [82, ""]);
+        });
+    },
+
+    resize: function () {
+        this.table.resize();
+    },
+
+    setColumnSize: function (columnSize) {
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    getCalculateColumnSize: function () {
+        return this.table.getCalculateColumnSize();
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize();
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize();
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        this.table.setLeftHorizontalScroll(scrollLeft);
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    resizeHeader: function () {
+        this.table.resize();
+        this.table._resizeHeader && this.table._resizeHeader();
+    },
+
+    attr: function (key,value) {
+        var self = this;
+        if (BI.isObject(key)) {
+            BI.each(key, function (k, v) {
+                self.attr(k, v);
+            });
+            return;
+        }
+        BI.ExcelTable.superclass.attr.apply(this, arguments);
+        switch (key){
+            case "mergeCols":
+                var mCols = [];
+                BI.each(value, function (i, col) {
+                    mCols.push(col + 1);
+                });
+                value=mCols;
+                break;
+        }
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    populate: function (rows) {
+        var self = this;
+        var columnSize = this.getColumnSize();
+        var items = [];
+        var header = [{
+            type: "bi.excel_table_header_cell"
+        }];
+        if (BI.isNotNull(rows)) {
+            BI.each(columnSize, function (i, size) {
+                header.push({
+                    type: "bi.excel_table_header_cell",
+                    text: BI.int2Abc(i + 1)
+                });
+            });
+            BI.each(rows, function (i, row) {
+                items.push([{
+                    type: "bi.excel_table_header_cell",
+                    text: (i + 1)
+                }].concat(row));
+            });
+        }
+        this.table.populate(items, [header]);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.ExcelTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.excel_table', BI.ExcelTable);
\ No newline at end of file
diff --git a/src/widget/filemanager/buttongroup.filemanager.js b/src/widget/filemanager/buttongroup.filemanager.js
new file mode 100644
index 000000000..6ef1ac7ab
--- /dev/null
+++ b/src/widget/filemanager/buttongroup.filemanager.js
@@ -0,0 +1,79 @@
+/**
+ * 文件管理控件组
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerButtonGroup
+ * @extends BI.Widget
+ */
+BI.FileManagerButtonGroup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerButtonGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-button_group",
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerButtonGroup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button_group = BI.createWidget({
+            type: "bi.button_tree",
+            element: this,
+            chooseType: BI.Selection.Multi,
+            items: this._formatItems(o.items),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _formatItems: function (items) {
+        var self = this, o = this.options;
+        BI.each(items, function (i, item) {
+            if (item.children && item.children.length > 0) {
+                item.type = "bi.file_manager_folder_item";
+            } else {
+                item.type = "bi.file_manager_file_item";
+            }
+        });
+        return items;
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getNotSelectedValue: function () {
+        return this.button_group.getNotSelectedValue();
+    },
+
+    getAllLeaves: function () {
+        return this.button_group.getAllLeaves();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    getSelectedButtons: function () {
+        return this.button_group.getSelectedButtons();
+    },
+
+    getNotSelectedButtons: function () {
+        return this.button_group.getNotSelectedButtons();
+    },
+
+    populate: function (items) {
+        this.button_group.populate(this._formatItems(items));
+    }
+});
+BI.FileManagerButtonGroup.EVENT_CHANGE = "FileManagerButtonGroup.EVENT_CHANGE";
+$.shortcut("bi.file_manager_button_group", BI.FileManagerButtonGroup);
\ No newline at end of file
diff --git a/src/widget/filemanager/filemanager.js b/src/widget/filemanager/filemanager.js
new file mode 100644
index 000000000..63c1f8ca9
--- /dev/null
+++ b/src/widget/filemanager/filemanager.js
@@ -0,0 +1,115 @@
+/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManager
+ * @extends BI.Widget
+ */
+BI.FileManager = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManager.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager",
+            el: {},
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManager.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = new BI.Tree();
+        var items = BI.Tree.transformToTreeFormat(o.items);
+        this.tree.initTree(items);
+        this.selectedValues = [];
+        this.nav = BI.createWidget({
+            type: "bi.file_manager_nav",
+            items: BI.deepClone(items)
+        });
+        this.nav.on(BI.FileManagerNav.EVENT_CHANGE, function (value, obj) {
+            if (value == "-1") {//根节点
+                self.populate({children: self.tree.toJSON()});
+            } else {
+                var node = self.tree.search(obj.attr("id"));
+                self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)}));
+            }
+            self.setValue(self.selectedValues);
+        });
+        this.list = BI.createWidget(o.el, {
+            type: "bi.file_manager_list",
+            items: items
+        });
+        this.list.on(BI.Controller.EVENT_CHANGE, function (type, selected, obj) {
+            if (type === BI.Events.CHANGE) {
+                var node = self.tree.search(obj.attr("id"));
+                self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)}));
+            } else if (type === BI.Events.CLICK) {
+                var values = [];
+                if (obj instanceof BI.MultiSelectBar) {
+                    var t = self.list.getValue();
+                    selected = t.type === BI.Selection.All;
+                    values = BI.concat(t.assist, t.value);
+                } else {
+                    values = obj.getAllLeaves();
+                }
+                BI.each(values, function (i, v) {
+                    if (selected === true) {
+                        self.selectedValues.pushDistinct(v);
+                    } else {
+                        self.selectedValues.remove(v);
+                    }
+                });
+            }
+            self.setValue(self.selectedValues);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.list,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 10
+            }, {
+                el: this.nav,
+                left: 40,
+                right: 100,
+                top: 0
+            }]
+        });
+    },
+
+    setValue: function (value) {
+        this.selectedValues = value || [];
+        this.list.setValue(this.selectedValues);
+    },
+
+    getValue: function () {
+        var obj = this.list.getValue();
+        var res = obj.type === BI.Selection.All ? obj.assist : obj.value;
+        res.pushDistinctArray(this.selectedValues);
+        return res;
+    },
+
+    _populate: function (items) {
+        this.list.populate(items);
+    },
+
+    getSelectedValue: function () {
+        return this.nav.getValue()[0];
+    },
+
+    getSelectedId: function () {
+        return this.nav.getId()[0];
+    },
+
+    populate: function (node) {
+        var clone = BI.deepClone(node);
+        this._populate(node.children);
+        this.nav.populate(clone);
+    }
+});
+BI.FileManager.EVENT_CHANGE = "FileManager.EVENT_CHANGE";
+$.shortcut("bi.file_manager", BI.FileManager);
\ No newline at end of file
diff --git a/src/widget/filemanager/items/item.file.filemanager.js b/src/widget/filemanager/items/item.file.filemanager.js
new file mode 100644
index 000000000..cfd9a8aca
--- /dev/null
+++ b/src/widget/filemanager/items/item.file.filemanager.js
@@ -0,0 +1,68 @@
+/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerFileItem
+ * @extends BI.Single
+ */
+BI.FileManagerFileItem = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerFileItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-file-item bi-list-item",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerFileItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checked = BI.createWidget({
+            type: "bi.multi_select_bar",
+            text: "",
+            width: 36,
+            height: o.height
+        });
+        this.checked.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.checked,
+                width: 36
+            }, {
+                el: {
+                    type: "bi.icon_button",
+                    cls: "create-by-me-file-font"
+                },
+                width: 20
+            }, {
+                el: {
+                    type: "bi.label",
+                    textAlign: "left",
+                    height: o.height,
+                    text: o.text,
+                    value: o.value
+                }
+            }]
+        })
+    },
+
+    getAllLeaves: function(){
+        return [this.options.value];
+    },
+
+    isSelected: function () {
+        return this.checked.isSelected();
+    },
+
+    setSelected: function (v) {
+        this.checked.setSelected(v);
+    }
+});
+BI.FileManagerFileItem.EVENT_CHANGE = "FileManagerFileItem.EVENT_CHANGE";
+$.shortcut("bi.file_manager_file_item", BI.FileManagerFileItem);
\ No newline at end of file
diff --git a/src/widget/filemanager/items/item.folder.filemanager.js b/src/widget/filemanager/items/item.folder.filemanager.js
new file mode 100644
index 000000000..b5a8d0841
--- /dev/null
+++ b/src/widget/filemanager/items/item.folder.filemanager.js
@@ -0,0 +1,153 @@
+/**
+ * 文件管理控件
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerFolderItem
+ * @extends BI.Single
+ */
+BI.FileManagerFolderItem = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerFolderItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-folder-item bi-list-item",
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerFolderItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checked = BI.createWidget({
+            type: "bi.multi_select_bar",
+            text: "",
+            width: 36,
+            height: o.height
+        });
+        this.checked.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            textAlign: "left",
+            height: o.height,
+            text: o.text,
+            value: o.value
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CHANGE, o.value, self);
+        });
+
+        this.tree = new BI.Tree();
+        this.tree.initTree([{
+            id: o.id,
+            children: o.children
+        }]);
+        this.selectValue = [];
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.checked,
+                width: 36
+            }, {
+                el: {
+                    type: "bi.icon_button",
+                    cls: "create-by-me-folder-font"
+                },
+                width: 20
+            }, {
+                el: this.button
+            }]
+        })
+    },
+
+    setAllSelected: function (v) {
+        this.checked.setSelected(v);
+        this.selectValue = [];
+    },
+
+    setHalfSelected: function (v) {
+        this.checked.setHalfSelected(v);
+        if(!v){
+            this.selectValue = [];
+        }
+    },
+
+    setValue: function (v) {
+        var self = this, o = this.options;
+        var isHalf = false;
+        var selectValue = [];
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                if (BI.contains(v, node.get("data").value)) {
+                    selectValue.push(node.get("data").value);
+                } else {
+                    isHalf = true;
+                }
+            }
+        });
+        this.setAllSelected(selectValue.length > 0 && !isHalf);
+        this.setHalfSelected(selectValue.length > 0 && isHalf);
+        if (this.checked.isHalfSelected()) {
+            this.selectValue = selectValue;
+        }
+    },
+
+    getAllButtons: function () {
+        return [this];
+    },
+
+    getAllLeaves: function () {
+        var o = this.options;
+        var res = [];
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                res.push(node.get("data").value)
+            }
+        });
+        return res;
+    },
+
+    getNotSelectedValue: function () {
+        var self = this, o = this.options;
+        var res = [];
+        var isAllSelected = this.checked.isSelected();
+        if (isAllSelected === true) {
+            return res;
+        }
+        var isHalfSelected = this.checked.isHalfSelected();
+        this.tree.traverse(function (node) {
+            if (node.isLeaf()) {
+                var v = node.get("data").value;
+                if (isHalfSelected === true) {
+                    if (!BI.contains(self.selectValue, node.get("data").value)) {
+                        res.push(v);
+                    }
+                } else {
+                    res.push(v);
+                }
+            }
+        });
+        return res;
+    },
+
+    getValue: function () {
+        var res = [];
+        if (this.checked.isSelected()) {
+            this.tree.traverse(function (node) {
+                if (node.isLeaf()) {
+                    res.push(node.get("data").value);
+                }
+            });
+            return res;
+        }
+        if (this.checked.isHalfSelected()) {
+            return this.selectValue;
+        }
+        return [];
+    }
+});
+BI.FileManagerFolderItem.EVENT_CHANGE = "FileManagerFolderItem.EVENT_CHANGE";
+$.shortcut("bi.file_manager_folder_item", BI.FileManagerFolderItem);
\ No newline at end of file
diff --git a/src/widget/filemanager/list.filemanager.js b/src/widget/filemanager/list.filemanager.js
new file mode 100644
index 000000000..ebe32dce3
--- /dev/null
+++ b/src/widget/filemanager/list.filemanager.js
@@ -0,0 +1,58 @@
+/**
+ * 文件管理控件列表
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerList
+ * @extends BI.Widget
+ */
+BI.FileManagerList = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-list",
+            el: {},
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerList.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.list = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            items: o.items,
+            toolbar: {
+                type: "bi.multi_select_bar",
+                height: 40,
+                text: ""
+            },
+            el: {
+                type: "bi.list_pane",
+                el: BI.isWidget(o.el) ? o.el : BI.extend({
+                    type: "bi.file_manager_button_group"
+                }, o.el)
+            }
+        });
+        this.list.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        this.list.setValue({
+            value: v
+        });
+    },
+
+    getValue: function () {
+        return this.list.getValue();
+    },
+
+    populate: function (items) {
+        this.list.populate(items);
+        this.list.setToolBarVisible(true);
+    }
+});
+BI.FileManagerList.EVENT_CHANGE = "FileManagerList.EVENT_CHANGE";
+$.shortcut("bi.file_manager_list", BI.FileManagerList);
\ No newline at end of file
diff --git a/src/widget/filemanager/nav/button/button.nav.filemanager.js b/src/widget/filemanager/nav/button/button.nav.filemanager.js
new file mode 100644
index 000000000..f430d4974
--- /dev/null
+++ b/src/widget/filemanager/nav/button/button.nav.filemanager.js
@@ -0,0 +1,92 @@
+/**
+ * 文件管理导航按钮
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerNavButton
+ * @extends BI.Widget
+ */
+BI.FileManagerNavButton = BI.inherit(BI.Widget, {
+
+    _const: {
+        normal_color: "#ffffff",
+        select_color: "#f4f4f4"
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerNavButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-nav-button",
+            selected: false,
+            height: 40
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerNavButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            cls: "file-manager-nav-button-text",
+            once: true,
+            selected: o.selected,
+            text: o.text,
+            title: o.text,
+            value: o.value,
+            height: o.height,
+            lgap: 20,
+            rgap: 10
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        var svg = BI.createWidget({
+            type: "bi.svg",
+            cls: "file-manager-nav-button-triangle",
+            width: 15,
+            height: o.height
+        });
+        var path = svg.path("M0,0L15,20L0,40").attr({
+            "stroke": c.select_color,
+            "fill": o.selected ? c.select_color : c.normal_color
+        });
+        this.button.on(BI.TextButton.EVENT_CHANGE, function () {
+            if (this.isSelected()) {
+                path.attr("fill", c.select_color);
+            } else {
+                path.attr("fill", c.normal_color);
+            }
+        });
+        BI.createWidget({
+            type: "bi.default",
+            element: this,
+            items: [this.button]
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: svg,
+                right: -15,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    isSelected: function () {
+        return this.button.isSelected();
+    },
+
+    setValue: function (v) {
+        this.button.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button.getValue();
+    },
+
+    populate: function (items) {
+
+    }
+});
+BI.FileManagerNavButton.EVENT_CHANGE = "FileManagerNavButton.EVENT_CHANGE";
+$.shortcut("bi.file_manager_nav_button", BI.FileManagerNavButton);
\ No newline at end of file
diff --git a/src/widget/filemanager/nav/nav.filemanager.js b/src/widget/filemanager/nav/nav.filemanager.js
new file mode 100644
index 000000000..30c1d6c92
--- /dev/null
+++ b/src/widget/filemanager/nav/nav.filemanager.js
@@ -0,0 +1,107 @@
+/**
+ * 文件管理导航
+ *
+ * Created by GUY on 2015/12/11.
+ * @class BI.FileManagerNav
+ * @extends BI.Widget
+ */
+BI.FileManagerNav = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.FileManagerNav.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-file-manager-nav",
+            height: 40,
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.FileManagerNav.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = new BI.Tree();
+        this.refreshTreeData(o.items);
+        this.tree.getRoot().set("data", {
+            text: BI.i18nText("BI-Created_By_Me"),
+            value: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+            id: BI.FileManagerNav.ROOT_CREATE_BY_ME
+        });
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: [{
+                type: "bi.file_manager_nav_button",
+                text: BI.i18nText("BI-Created_By_Me"),
+                selected: true,
+                id: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+                value: BI.FileManagerNav.ROOT_CREATE_BY_ME
+            }],
+            layouts: [{
+                type: "bi.horizontal"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+            self.fireEvent(BI.FileManagerNav.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _getAllParents: function (id) {
+        var node, res = [];
+        if (!id) {
+            node = this.tree.getRoot();
+        } else {
+            node = this.tree.search(id);
+        }
+        while (node.parent) {
+            res.push(node);
+            node = node.parent;
+        }
+        res.push(node);
+        return res.reverse();
+    },
+
+    _formatNodes: function (nodes) {
+        var res = [];
+        BI.each(nodes, function (i, node) {
+            res.push(BI.extend({
+                type: "bi.file_manager_nav_button",
+                id: node.id
+            }, node.get("data")));
+        });
+        BI.last(res).selected = true;
+        return res;
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getId: function () {
+        var ids = [];
+        BI.each(this.button_group.getSelectedButtons(), function (i, btn) {
+            ids.push(btn.attr("id"));
+        });
+        return ids;
+    },
+
+    refreshTreeData: function(items){
+        this.tree.initTree(BI.Tree.transformToTreeFormat(items));
+        this.tree.getRoot().set("data", {
+            text: BI.i18nText("BI-Created_By_Me"),
+            value: BI.FileManagerNav.ROOT_CREATE_BY_ME,
+            id: BI.FileManagerNav.ROOT_CREATE_BY_ME
+        });
+    },
+
+    populate: function (node) {
+        var parents = BI.isNull(node) ? [this.tree.getRoot()] : this._getAllParents(node.id);
+        this.button_group.populate(this._formatNodes(parents));
+    }
+});
+BI.extend(BI.FileManagerNav, {
+    ROOT_CREATE_BY_ME: "-1"
+});
+BI.FileManagerNav.EVENT_CHANGE = "FileManagerNav.EVENT_CHANGE";
+$.shortcut("bi.file_manager_nav", BI.FileManagerNav);
\ No newline at end of file
diff --git a/src/widget/filterpane/abstract.item.filter.js b/src/widget/filterpane/abstract.item.filter.js
new file mode 100644
index 000000000..d6ce85bfe
--- /dev/null
+++ b/src/widget/filterpane/abstract.item.filter.js
@@ -0,0 +1,49 @@
+/**
+ * 过滤条件抽象类
+ *
+ * @class BI.AbstractFilterItem
+ * @extend BI.Widget
+ */
+BI.AbstractFilterItem = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.AbstractFilterItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-item"
+        })
+    },
+
+    _init: function () {
+        BI.AbstractFilterItem.superclass._init.apply(this, arguments);
+    },
+
+    isSelectedCondition: function () {
+        return this.emptyItem && this.emptyItem.isVisible();
+    },
+
+    setSelectedCondition: function (b) {
+        if (!!b) {
+            if (!this.emptyItem) {
+                this.emptyItem = BI.createWidget({
+                    type: "bi.absolute",
+                    height: 40,
+                    cls: "filter-item-empty-item",
+                    items: [{
+                        el: {
+                            type: "bi.center_adapt",
+                            cls: "empty-filter-item-leaf"
+                        }
+                    }],
+                    hgap: 10,
+                    vgap: 5
+                });
+                BI.createWidget({
+                    type: "bi.vertical",
+                    element: this,
+                    items: [this.emptyItem],
+                    scrolly: false
+                });
+            }
+        }
+        this.emptyItem && this.emptyItem.setVisible(b);
+    }
+});
\ No newline at end of file
diff --git a/src/widget/filterpane/expander.filter.js b/src/widget/filterpane/expander.filter.js
new file mode 100644
index 000000000..d534f8f64
--- /dev/null
+++ b/src/widget/filterpane/expander.filter.js
@@ -0,0 +1,79 @@
+/**
+ * @class BI.FilterExpander
+ * @extend BI.AbstractFilterItem
+ * 过滤树的一个expander节点
+ */
+BI.FilterExpander = BI.inherit(BI.AbstractFilterItem, {
+
+    _constant: {
+        EXPANDER_WIDTH: 20
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.FilterExpander.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-filter-expander",
+            el: {},
+            popup: {}
+        })
+    },
+
+    _init: function () {
+        BI.FilterExpander.superclass._init.apply(this, arguments);
+        this._initExpander();
+        this._initConditionsView();
+        BI.createWidget({
+            type: "bi.horizontal_adapt",
+            element: this,
+            items: [this.expander, this.conditionsView]
+        });
+    },
+
+    _initExpander: function () {
+        var self = this, o = this.options;
+        var value = o.value, text = "";
+        if (value === BICst.FILTER_TYPE.AND) {
+            text = BI.i18nText("BI-Basic_And");
+        } else {
+            text = BI.i18nText("BI-Basic_Or");
+        }
+        this.expander = BI.createWidget({
+            type: "bi.text_button",
+            cls: "condition-and-or",
+            text: text,
+            value: value,
+            id: o.id,
+            width: this._constant.EXPANDER_WIDTH,
+            height: "100%"
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            arguments[2] = self;
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _initConditionsView: function () {
+        var self = this, popup = this.options.popup;
+        this.conditionsView = BI.createWidget(popup);
+        this.conditionsView.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    getValue: function () {
+        return {
+            type: this.expander.getValue(),
+            value: this.conditionsView.getValue(),
+            id: this.options.id
+        };
+    },
+
+    setValue: function () {
+
+    },
+
+    populate: function (items) {
+        this.conditionsView.populate.apply(this.conditionsView, arguments);
+    }
+});
+$.shortcut("bi.filter_expander", BI.FilterExpander);
\ No newline at end of file
diff --git a/src/widget/filterpane/filter.js b/src/widget/filterpane/filter.js
new file mode 100644
index 000000000..30e113cf1
--- /dev/null
+++ b/src/widget/filterpane/filter.js
@@ -0,0 +1,181 @@
+/**
+ * 过滤
+ *
+ * Created by GUY on 2015/11/20.
+ * @class BI.Filter
+ * @extend BI.Widget
+ */
+BI.Filter = BI.inherit(BI.Widget, {
+
+    constants: {
+        FIELD_TYPE_NUMBER: 1,
+        FIELD_TYPE_STRING: 0,
+        FIELD_TYPE_DATE: 2
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Filter.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter",
+            expander: {},
+            items: [],
+            el: {},
+            itemCreator: BI.empty
+        })
+    },
+
+    _init: function () {
+        BI.Filter.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.filter = BI.createWidget(o.el,{
+            type: "bi.filter_operation",
+            expander: o.expander,
+            items: o.items,
+            element: this
+        });
+        this.filter.on(BI.FilterOperation.EVENT_OPERATION, function (type) {
+            switch (type) {
+                case BICst.FILTER_OPERATION_CONDITION:
+                case BICst.FILTER_OPERATION_CONDITION_AND:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_CONDITION);
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION_OR:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_CONDITION, 1);
+                    break;
+                case BICst.FILTER_OPERATION_FORMULA:
+                case BICst.FILTER_OPERATION_FORMULA_AND:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_FORMULA);
+                    break;
+                case BICst.FILTER_OPERATION_FORMULA_OR:
+                    self._addAndOrCondition(BICst.FILTER_TYPE.EMPTY_FORMULA, 1);
+                    break;
+            }
+        });
+        this.filter.on(BI.FilterOperation.EVENT_DESTROY_ITEM, function (id) {
+            self._removeCondition(id);
+        });
+
+        this.tree = new BI.Tree();
+        this.tree.initTree(o.items);
+    },
+
+    _removeCondition: function (id) {
+        var finded = this.tree.search(id);
+        if (BI.isNotNull(finded)) {
+            var parent = finded.getParent();
+            parent.removeChild(id);
+            if (parent.getChildrenLength() <= 1) {
+                var prev = parent.getParent();
+                if (BI.isNotNull(prev)) {
+                    var index = prev.getChildIndex(parent.id);
+                    prev.removeChildByIndex(index);
+                    if (parent.getChildrenLength() === 1) {
+                        prev.addChild(parent.getFirstChild(), index);
+                    }
+                }
+            }
+            this._populate(this.tree.toJSONWithNode());
+            this.fireEvent(BI.Filter.EVENT_CHANGE);
+        }
+    },
+
+    _createEmptyNode: function (type) {
+        var node = new BI.Node(BI.UUID());
+        node.set("data", {
+            value: type
+        });
+        return node;
+    },
+
+    _insertAndOrCondition: function (id, formulaOrField, type) {
+        var ANDOR = ["AND", "OR"];
+        type || (type = 0);
+        var finded = this.tree.search(id);
+        if (BI.isNotNull(finded)) {
+            var data = finded.get("data");
+            var parent = finded.getParent();
+            var index = parent.getChildIndex(finded.id);
+            var pdata = parent.get("data") || {};
+            var node = this._createEmptyNode(formulaOrField);
+            if (data.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                this.tree.addNode(finded, node);
+                return;
+            }
+            if (data.value === BICst.FILTER_TYPE[ANDOR[1 - type]]) {
+                if (pdata.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                    parent.addChild(node, index + 1);
+                    return;
+                }
+            }
+            if ((data.value === BICst.FILTER_TYPE[ANDOR[1 - type]] && pdata.value !== BICst.FILTER_TYPE[ANDOR[type]])
+                || pdata.value === BICst.FILTER_TYPE[ANDOR[1 - type]]
+                || (pdata.value !== BICst.FILTER_TYPE.AND && pdata.value !== BICst.FILTER_TYPE.OR)) {
+                var andor = new BI.Node(BI.UUID());
+                andor.set("data", {
+                    value: BICst.FILTER_TYPE[ANDOR[type]],
+                    children: [finded.get("data"), node.get("data")]
+                });
+                parent.removeChildByIndex(index);
+                parent.addChild(andor, index);
+                andor.addChild(finded);
+                andor.addChild(node);
+                return;
+            }
+            parent.addChild(node, index + 1);
+        }
+    },
+
+    _addAndOrCondition: function (formulaOrField, type) {
+        var ANDOR = ["AND", "OR"];
+        type || (type = 0);
+        var o = this.options;
+        var currentSelectItem = this.filter.getCurrentSelectItem();
+        if (BI.isNotNull(currentSelectItem)) {
+            var id = currentSelectItem.attr("id");
+            this._insertAndOrCondition(id, formulaOrField, type);
+        } else {
+            var node = this._createEmptyNode(formulaOrField);
+            var root = this.tree.getRoot();
+            var child = root.getLastChild();
+            if (BI.isNotNull(child)) {
+                var data = child.get("data");
+                if (data.value === BICst.FILTER_TYPE[ANDOR[type]]) {
+                    this.tree.addNode(child, node);
+                } else {
+                    var andor = new BI.Node(BI.UUID());
+                    andor.set("data", {
+                        value: BICst.FILTER_TYPE[ANDOR[type]],
+                        children: [child.get("data"), node.get("data")]
+                    });
+                    root.removeChild(child.id);
+                    this.tree.addNode(andor);
+                    this.tree.addNode(andor, child);
+                    this.tree.addNode(andor, node);
+                }
+            } else {
+                this.tree.addNode(node);
+            }
+        }
+        this._populate(this.tree.toJSONWithNode());
+        this.fireEvent(BI.Filter.EVENT_CHANGE);
+    },
+
+    _populate: function (items) {
+        var self = this, o = this.options;
+        o.items = items;
+        ArrayUtils.traversal(items, function (i, item) {
+            o.itemCreator(item);
+        });
+        this.filter.populate.apply(this.filter, [items]);
+    },
+
+    populate: function (conditions) {
+        this.tree.initTree(conditions);
+        this._populate(this.tree.toJSONWithNode());
+    },
+
+    getValue: function () {
+        return this.filter.getValue();
+    }
+});
+BI.Filter.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.filter", BI.Filter);
\ No newline at end of file
diff --git a/src/widget/filterpane/operation.filter.js b/src/widget/filterpane/operation.filter.js
new file mode 100644
index 000000000..b339777ab
--- /dev/null
+++ b/src/widget/filterpane/operation.filter.js
@@ -0,0 +1,219 @@
+/**
+ * 过滤条件
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.FilterOperation
+ * @extend BI.Widget
+ */
+BI.FilterOperation = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FilterOperation.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-operation",
+            expander: {},
+            items: [],
+            selections: [BICst.FILTER_OPERATION_CONDITION, BICst.FILTER_OPERATION_FORMULA],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _defaultState: function () {
+        if (BI.isNotNull(this.currentSelected)) {
+            this.currentSelected.setSelectedCondition(false);
+        }
+        this.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+    },
+
+    _init: function () {
+        BI.FilterOperation.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.currentSelected = null;
+
+        this.filter = BI.createWidget({
+            type: "bi.filter_pane",
+            expander: o.expander,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+        this.filter.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+            if (type === BI.Events.CLICK) {
+                if (BI.isNotNull(self.currentSelected) && self.currentSelected === obj) {
+                    obj.setSelectedCondition(!obj.isSelectedCondition());
+                } else {
+                    if (BI.isNotNull(self.currentSelected)) {
+                        self.currentSelected.setSelectedCondition(false);
+                    }
+                    self.currentSelected = obj;
+                    obj.setSelectedCondition(true);
+                }
+                if (self.currentSelected.isSelectedCondition()) {
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_ANDOR_CONDITION);
+                } else {
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+                }
+            }
+            if (type === BI.Events.DESTROY) {
+                if (self.currentSelected === obj) {
+                    self.currentSelected = null;
+                    self.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+                }
+                self.fireEvent(BI.FilterOperation.EVENT_DESTROY_ITEM, value, obj);
+            }
+        });
+        this.filter.on(BI.FilterPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FilterOperation.EVENT_CHANGE, arguments);
+        });
+        var operation = this._buildOperationTab();
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: operation,
+                height: 40
+            }, {
+                el: {
+                    type: "bi.absolute",
+                    scrollable: true,
+                    items: [{
+                        el: {
+                            type: "bi.left",
+                            items: [
+                                this.filter
+                            ]
+                        },
+                        top: 0,
+                        right: 2,
+                        bottom: 0,
+                        left: 0
+                    }]
+                }
+            }]
+        })
+    },
+
+    _buildOperationTab: function () {
+        this.buttonComboTab = BI.createWidget({
+            type: "bi.tab",
+            tab: null,
+            cardCreator: BI.bind(this._createTabs, this)
+        });
+        this.buttonComboTab.setSelect(BI.FilterOperation.OPERATION_ADD_CONDITION);
+        return this.buttonComboTab;
+    },
+
+    _createTabs: function (v) {
+        var self = this;
+        switch (v) {
+            case BI.FilterOperation.OPERATION_ADD_CONDITION:
+                var btnGroup = BI.createWidget({
+                    type: "bi.button_group",
+                    items: BI.createItems(self._createButtons(), {
+                        type: "bi.button",
+                        forceNotSelected: true,
+                        level: "ignore",
+                        height: 25
+                    }),
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                    layouts: [{
+                        type: "bi.right",
+                        hgap: 10,
+                        vgap: 5
+                    }]
+                });
+                btnGroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) {
+                    self.fireEvent(BI.FilterOperation.EVENT_OPERATION, obj.getValue());
+                    self._defaultState();
+                });
+                return btnGroup;
+            case BI.FilterOperation.OPERATION_ADD_ANDOR_CONDITION:
+                var btnGroup = BI.createWidget({
+                    type: "bi.button_group",
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                    items: self._createCombos(),
+                    layouts: [{
+                        type: "bi.right",
+                        hgap: 10,
+                        vgap: 5
+                    }]
+                });
+                return btnGroup;
+        }
+    },
+
+    _createButtons: function(){
+        var buttons = [];
+        BI.each(this.options.selections, function(i, type){
+            switch (type){
+                case BICst.FILTER_OPERATION_FORMULA:
+                    buttons.push({
+                        text: BI.i18nText("BI-Add_Formula"),
+                        value: BICst.FILTER_OPERATION_FORMULA
+                    });
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION:
+                    buttons.push({
+                        text: BI.i18nText("BI-Add_Condition"),
+                        value: BICst.FILTER_OPERATION_CONDITION
+                    });
+                    break;
+            }
+        });
+        return buttons;
+    },
+
+    _createCombos: function () {
+        var self = this, combos = [];
+        BI.each(this.options.selections, function(i, type){
+            var text = "", items = [];
+            switch (type) {
+                case BICst.FILTER_OPERATION_FORMULA:
+                    text = BI.i18nText("BI-Add_Formula");
+                    items = BICst.FILTER_ADD_FORMULA_COMBO;
+                    break;
+                case BICst.FILTER_OPERATION_CONDITION:
+                    text = BI.i18nText("BI-Add_Condition");
+                    items = BICst.FILTER_ADD_CONDITION_COMBO;
+                    break;
+            }
+            var addCombo = BI.createWidget({
+                type: "bi.static_combo",
+                text: text,
+                width: 90,
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_NONE,
+                items: BI.createItems(items, {
+                    type: "bi.single_select_item",
+                    height: 25
+                })
+            });
+            addCombo.on(BI.Combo.EVENT_CHANGE, function (value, obj) {
+                self.fireEvent(BI.FilterOperation.EVENT_OPERATION, obj.getValue());
+                self._defaultState();
+            });
+            combos.push(addCombo);
+        });
+        return combos;
+    },
+
+    getCurrentSelectItem: function () {
+        if (BI.isNotNull(this.currentSelected) && this.currentSelected.isSelectedCondition()) {
+            return this.currentSelected;
+        }
+    },
+
+    populate: function (items) {
+
+        this.filter.populate.apply(this.filter, arguments);
+    },
+
+    getValue: function () {
+        return this.filter.getValue();
+    }
+});
+BI.extend(BI.FilterOperation, {
+    OPERATION_ADD_CONDITION: 0,
+    OPERATION_ADD_ANDOR_CONDITION: 1
+});
+BI.FilterOperation.EVENT_OPERATION = "EVENT_OPERATION";
+BI.FilterOperation.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FilterOperation.EVENT_DESTROY_ITEM = "BI.FilterOperation.EVENT_DESTROY_ITEM";
+$.shortcut("bi.filter_operation", BI.FilterOperation);
\ No newline at end of file
diff --git a/src/widget/filterpane/pane.filter.js b/src/widget/filterpane/pane.filter.js
new file mode 100644
index 000000000..12c91e978
--- /dev/null
+++ b/src/widget/filterpane/pane.filter.js
@@ -0,0 +1,60 @@
+/**
+ * @class BI.FilterPane
+ * @extend BI.Widget
+ * 过滤面板
+ */
+BI.FilterPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FilterPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-filter-pane",
+            expander: {},
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.FilterPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.filter_expander",
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            }, o.expander),
+            el: {
+                type: "bi.button_map",
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_DEFAULT,
+                layouts: [{
+                    type: "bi.vertical",
+                    scrolly: false
+                }]
+            }
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.FilterPane.EVENT_CHANGE, [].slice.call(arguments, 1));
+            }
+        });
+
+        if (BI.isNotEmptyArray(o.items)) {
+            this.populate(o.items);
+        }
+    },
+
+    populate: function (items) {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    }
+});
+BI.FilterPane.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.filter_pane", BI.FilterPane);
\ No newline at end of file
diff --git a/src/widget/finetuningnumbereditor/finetuning.number.editor.js b/src/widget/finetuningnumbereditor/finetuning.number.editor.js
new file mode 100644
index 000000000..0f4f6a35e
--- /dev/null
+++ b/src/widget/finetuningnumbereditor/finetuning.number.editor.js
@@ -0,0 +1,95 @@
+/**
+ * Created by windy on 2017/3/13.
+ * 数值微调器
+ */
+BI.FineTuningNumberEditor = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.FineTuningNumberEditor.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-fine-tuning-number-editor",
+            value: -1
+        })
+    },
+
+    _init: function () {
+        BI.FineTuningNumberEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            value: this._alertInEditorValue(o.value),
+            errorText: BI.i18nText("BI-Please_Input_Natural_Number"),
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v) || self._alertOutEditorValue(v) === -1;
+            }
+        });
+        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function(){
+            self._finetuning(0);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this.topBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "column-pre-page-h-font top-button"
+        });
+        this.topBtn.on(BI.IconButton.EVENT_CHANGE, function(){
+            self._finetuning(1);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this.bottomBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "column-next-page-h-font bottom-button"
+        });
+        this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function(){
+            self._finetuning(-1);
+            self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM);
+        });
+        this._finetuning(0);
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [this.editor, {
+                el: {
+                    type: "bi.grid",
+                    columns: 1,
+                    rows: 2,
+                    items: [{
+                        column: 0,
+                        row: 0,
+                        el: this.topBtn
+                    }, {
+                        column: 0,
+                        row: 1,
+                        el: this.bottomBtn
+                    }]
+                },
+                width: 30
+            }]
+        });
+    },
+
+    _alertOutEditorValue: function(v){
+        return v === BI.i18nText("BI-Basic_Auto") ? -1 : v;
+    },
+
+    _alertInEditorValue: function(v){
+        return BI.parseInt(v) === -1 ? BI.i18nText("BI-Basic_Auto") : v;
+    },
+
+    //微调
+    _finetuning: function(add){
+        var v = BI.parseInt(this._alertOutEditorValue(this.editor.getValue()));
+        this.editor.setValue(this._alertInEditorValue(v + add));
+        this.bottomBtn.setEnable((v + add) !== -1);
+    },
+
+    getValue: function () {
+        var v = this.editor.getValue();
+        return this._alertOutEditorValue(v);
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(this._alertInEditorValue(v));
+        this._finetuning(0);
+    }
+
+});
+BI.FineTuningNumberEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.fine_tuning_number_editor", BI.FineTuningNumberEditor);
\ No newline at end of file
diff --git a/src/widget/formula/group.symbol.js b/src/widget/formula/group.symbol.js
new file mode 100644
index 000000000..38e089663
--- /dev/null
+++ b/src/widget/formula/group.symbol.js
@@ -0,0 +1,66 @@
+/**
+ * Created by roy on 15/9/29.
+ */
+/**
+ * Created by roy on 15/9/1.
+ */
+BI.SymbolGroup = BI.inherit(BI.Widget, {
+    constants: {
+        hgap: 7.5,
+        textWidth: 14,
+        textHeight: 17
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.SymbolGroup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-symbol-group"
+        })
+    },
+    _init: function () {
+        BI.SymbolGroup.superclass._init.apply(this, arguments)
+        var self = this, c = this.constants;
+
+        var items = [{
+            text: "+",
+            value: "+"
+        }, {
+            text: "-",
+            value: "-"
+        }, {
+            text: "*",
+            value: "*"
+        }, {
+            text: "/",
+            value: "/"
+        }, {
+            text: "(",
+            value: "("
+        }, {
+            text: ")",
+            value: ")"
+        }];
+
+        this.symbolgroup = BI.createWidget({
+            type: "bi.button_group",
+            element: self,
+            chooseType:-1,
+            items: BI.createItems(items, {
+                type: "bi.text_button",
+                forceNotSelected: true,
+                once: false,
+                textWidth: c.textWidth,
+                textHeight: c.textHeight,
+                cls: "symbol-button"
+            }),
+            layouts: [{
+                type: "bi.left_vertical_adapt",
+                hgap: c.hgap
+            }]
+        });
+
+        this.symbolgroup.on(BI.ButtonGroup.EVENT_CHANGE,function(v){
+            self.fireEvent(BI.SymbolGroup.EVENT_CHANGE,v)
+        })
+    }
+});
+BI.SymbolGroup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.symbol_group", BI.SymbolGroup);
\ No newline at end of file
diff --git a/src/widget/formula/insert.formula.js b/src/widget/formula/insert.formula.js
new file mode 100644
index 000000000..38f4d80b3
--- /dev/null
+++ b/src/widget/formula/insert.formula.js
@@ -0,0 +1,343 @@
+/**
+ * Created by roy on 15/9/9.
+ */
+//0更多函数为展开状态,1为函数框展开,显示返回状态
+BI.FormulaInsert = BI.inherit(BI.Widget, {
+    constants: {
+        right_set_off: -322,
+        height: 30,
+        width: 160,
+        right: 10,
+        button_bottom: 5,
+        pane_bottom: -1,
+        retract: 1,
+        more_function: 0,
+        functionTypes: ["MATH", "DATETIME", "ARRAY", "TEXT", "LOGIC", "OTHER"],
+        abandonFunctions: ["ACOS", "ACOSH", "ASIN", "ASINH", "ATAN", "ATAN2", "ATANH", "BITNOT", "BITOPERATION", "CHAR", "CLASS", "CODE", "COMBIN", "CORREL", "COS", "COSH", "DATETONUMBER", "DEGREES", "GETKEY", "GETUSERDEPARTMENTS", "GETUSERJOBTITLES", "NVL", "ODD", "PI", "POWER", "PRODUCT", "PROPER", "RADIANS", "REGEXP", "REVERSE", "RemoteIP", "SIN", "SINH", "STARTWITH", "TAN", "TANH", "TESTCONNECTION", "TESTMACANDUUID", "TOBINARY", "TOHEX", "TOOCTAL", "TOIMAGE"]
+    },
+
+    _defaultConfig: function () {
+        var conf = BI.FormulaInsert.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-formula-insert",
+            fieldItems: []
+
+
+        })
+    },
+
+    _init: function () {
+        BI.FormulaInsert.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this.constants;
+        self.validation = "valid";
+
+        this.formulatree = BI.createWidget({
+            type: "bi.formula_field_tree",
+            cls: "bi-formula-field-pane",
+            items: o.fieldItems
+        });
+
+        this.formulatree.on(BI.FormulaFieldTree.EVENT_CHANGE, function () {
+            var v = self.formulatree.getValue();
+            self.formulaedit.insertField(self.fieldValueTextMap[v[0]]);
+        });
+
+        this.symbolgroup = BI.createWidget({
+            type: "bi.symbol_group",
+            height: c.height,
+            cls: "symbol-group-column"
+        });
+
+        this.symbolgroup.on(BI.SymbolGroup.EVENT_CHANGE, function (v) {
+            self.formulaedit.insertOperator(v);
+        });
+
+
+        this.formulaedit = BI.createWidget({
+            type: "bi.formula",
+            tipType: "warning",
+            watermark: BI.i18nText("BI-Formula_Water_Mark")
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_CHANGE, function () {
+            if (BI.Func.checkFormulaValidation(self.formulaedit.getCheckString())) {
+                self.validation = "valid";
+                BI.Bubbles.hide(self.getName() + "invalid");
+            } else {
+                BI.Bubbles.show(self.getName() + "invalid", BI.i18nText("BI-Formula_Valid"), self, {
+                    offsetStyle: "center"
+                });
+                self.validation = "invalid"
+            }
+            self.fireEvent(BI.FormulaInsert.EVENT_CHANGE);
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_BLUR, function () {
+            BI.Bubbles.hide(self.getName() + "invalid");
+            if (!self.checkValidation()) {
+                self.formulaedit.setTitle(BI.i18nText("BI-Formula_Valid"), {belowMouse: true});
+            }
+
+
+        });
+
+        this.formulaedit.on(BI.FormulaEditor.EVENT_FOCUS, function () {
+            self.formulaedit.setTitle("");
+            if (!self.checkValidation()) {
+                BI.Bubbles.show(self.getName() + "invalid", BI.i18nText("BI-Formula_Valid"), self, {offsetStyle: "center"});
+            }
+        });
+
+        this.editorpane = BI.createWidget({
+            type: "bi.vtape",
+
+            items: [
+                {
+                    height: "fill",
+                    el: self.formulaedit
+                }, {
+                    height: c.height,
+                    el: self.symbolgroup
+                }
+            ]
+        });
+
+
+        this.functionbutton = BI.createWidget({
+            type: "bi.text_button",
+            text: BI.i18nText("BI-Formula_More_Function"),
+            value: c.more_function,
+            cls: "more-function-button"
+        });
+
+        this.functionpane = BI.createWidget({
+            type: "bi.function_pane",
+            items: self._createFunctionItems(),
+        });
+
+        this.functionCombo = BI.createWidget({
+            type: "bi.combo",
+            isNeedAdjustWidth: false,
+            el: this.functionbutton,
+            direction: "right,top",
+            adjustYOffset: -16,
+            adjustXOffset: 10,
+            hideChecker: function () {
+                return false;
+            },
+            popup: {
+                el: self.functionpane,
+                width: 372
+            },
+            width: 65
+        });
+
+
+        BI.createWidget({
+            element: this,
+            type: "bi.htape",
+            items: [
+                {
+                    width: c.width,
+                    el: self.formulatree
+                },
+                {
+
+                    el: self.editorpane
+                }
+            ],
+            height: o.height,
+            width: o.width
+        });
+        BI.createWidget({
+            element: this,
+            type: "bi.absolute",
+            items: [
+                {
+                    el: self.functionCombo,
+                    right: c.right,
+                    bottom: c.button_bottom
+                }
+            ]
+        });
+
+
+        self.formulaedit.element.droppable({
+            accept: ".bi-tree-text-leaf-item",
+            drop: function (event, ui) {
+                var value = ui.helper.attr("text");
+                self.formulaedit.insertField(value);
+            }
+        });
+
+
+        this.functionCombo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.functionbutton.setText(BI.i18nText("BI-Formula_Retract"))
+        });
+
+        this.functionCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.functionbutton.setText(BI.i18nText("BI-Formula_More_Function"))
+        });
+
+        this.functionpane.on(BI.FunctionPane.EVENT_INSET, function (v) {
+            if (BI.isNotEmptyString(v)) {
+                self.formulaedit.insertFunction(v);
+            }
+
+        });
+
+        this.populate(o.fieldItems);
+
+    },
+
+
+    _isFunction: function (str) {
+        var self = this, o = this.options, result = false;
+        BI.each(o.functionItems, function (i, item) {
+            var text = item.text.toLowerCase();
+            var lowerString = str.toLowerCase();
+            if (text === lowerString) {
+                result = true
+            }
+        });
+        return result;
+    },
+
+    _analyzeContent: function (v) {
+        var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)|\n/g;
+        return v.match(regx);
+    },
+
+    _getFunctionType: function (functionType) {
+        switch (functionType) {
+            case  "MATH":
+                return BICst.FUNCTION.MATH;
+            case "TEXT":
+                return BICst.FUNCTION.TEXT;
+            case "DATETIME":
+                return BICst.FUNCTION.DATE;
+            case "ARRAY":
+                return BICst.FUNCTION.ARRAY;
+            case "LOGIC":
+                return BICst.FUNCTION.LOGIC;
+            case "OTHER":
+                return BICst.FUNCTION.OTHER;
+        }
+    },
+
+    _createFunctionItems: function () {
+        var self = this;
+        var functionObjs = FormulaJSONs;
+        var functionItems = [];
+        BI.each(functionObjs, function (i, functionObj) {
+            if (self.constants.functionTypes.contains(functionObj.type) && !self.constants.abandonFunctions.contains(functionObj.name)) {
+                var item = {};
+                item.text = functionObj.name;
+                item.value = functionObj.name;
+                item.fieldType = self._getFunctionType(functionObj.type);
+                item.description = functionObj.def;
+                item.title = functionObj.def;
+                functionItems.push(item);
+            }
+        });
+        this.options.functionItems = functionItems;
+        return functionItems;
+    },
+
+    _createFieldTextValueMap: function (fieldItems) {
+        var fieldMap = {};
+        BI.each(fieldItems, function(idx, typeItems){
+            BI.each(typeItems, function (i, fieldItem) {
+                fieldMap[fieldItem.text] = fieldItem.value;
+            });
+        })
+        return fieldMap;
+    },
+
+    _createFieldValueTextMap: function (fieldItems) {
+        var fieldMap = {};
+        BI.each(fieldItems, function (idx, typeItems) {
+            BI.each(typeItems, function (i, fieldItem) {
+                fieldMap[fieldItem.value] = fieldItem.text;
+            })
+        });
+        return fieldMap;
+    },
+
+    _bindDragEvent: function () {
+        var self = this;
+        BI.each(self.formulatree.getAllLeaves(), function (i, node) {
+            node.element.draggable({
+                cursorAt: {top: 5, left: 5},
+                helper: function () {
+                    var hint = BI.createWidget({
+                        type: "bi.helper",
+                        value: node.getValue(),
+                        text: self.fieldValueTextMap[node.getValue()]
+                    });
+                    BI.createWidget({
+                        element: self,
+                        type: "bi.default",
+                        items: [hint]
+                    });
+                    hint.element.attr({text: self.fieldValueTextMap[node.getValue()]});
+                    return hint.element;
+
+                }
+            })
+
+        });
+    },
+
+
+    checkValidation: function () {
+        return this.validation === "valid";
+    },
+
+    refresh: function () {
+        this.formulaedit.refresh();
+    },
+
+    setValue: function (v) {
+        var self = this, result;
+        self.formulaedit.refresh();
+        self.formulaedit.setValue("");
+        result = this._analyzeContent(v || "");
+        BI.each(result, function (i, item) {
+            var fieldRegx = /\$[\{][^\}]*[\}]/;
+            var str = item.match(fieldRegx);
+            if (BI.isNotEmptyArray(str)) {
+                self.formulaedit.insertField(self.fieldValueTextMap[str[0].substring(2, item.length - 1)]);
+            } else if (self._isFunction(item)) {
+                self.formulaedit.setFunction(item);
+            } else {
+                self.formulaedit.insertString(item);
+            }
+        })
+
+    },
+
+    getFormulaString: function () {
+        return this.formulaedit.getFormulaString();
+    },
+
+    getUsedFields: function () {
+        return this.formulaedit.getUsedFields();
+    },
+
+    getValue: function () {
+        return this.formulaedit.getValue();
+    },
+    populate: function (fieldItems) {
+        this.options.fieldItems = fieldItems;
+        this.fieldTextValueMap = this._createFieldTextValueMap(fieldItems);
+        this.fieldValueTextMap = this._createFieldValueTextMap(fieldItems);
+        this.formulaedit.setFieldTextValueMap(this.fieldTextValueMap);
+        this.formulatree.populate(fieldItems);
+        this._bindDragEvent();
+    }
+
+
+});
+BI.FormulaInsert.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_insert", BI.FormulaInsert);
\ No newline at end of file
diff --git a/src/widget/formula/item.button.text.treeleaf.js b/src/widget/formula/item.button.text.treeleaf.js
new file mode 100644
index 000000000..a13e2c2cb
--- /dev/null
+++ b/src/widget/formula/item.button.text.treeleaf.js
@@ -0,0 +1,97 @@
+BI.ButtonTextTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ButtonTextTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-button-text-tree-item ",
+            id: "",
+            pId: "",
+            height: 25,
+            hgap: 0,
+            lgap: 0,
+            rgap: 0
+        })
+    },
+    _init: function () {
+        BI.ButtonTextTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            lgap: o.lgap,
+            rgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.button = BI.createWidget({
+            type: "bi.text_button",
+            height: 25,
+            stopEvent:true,
+            value: BI.i18nText("BI-Formula_Insert"),
+            cls: "formula-function-insert-button"
+        });
+        this.button.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.ADD, self.text.getText());
+        });
+        this.button.invisible();
+        this.leaf = BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: this.button,
+                width: 30
+            }, {
+                el: this.text
+            }],
+            hgap: o.hgap
+        })
+        this.element.hover(function () {
+            self.button.visible();
+        }, function () {
+            if (!self.isSelected()) {
+                self.button.invisible();
+            }
+
+        })
+
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doHighLight: function () {
+        this.text.doHighLight.apply(this.text, arguments);
+    },
+
+    unHighLight: function () {
+        this.text.unHighLight.apply(this.text, arguments);
+    },
+
+    setSelected: function (b) {
+        BI.ButtonTextTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        if (BI.isNotNull(b) && b === true) {
+            this.button.visible();
+        } else {
+            this.button.invisible();
+        }
+    },
+
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    }
+});
+
+$.shortcut("bi.button_text_tree_leaf_item", BI.ButtonTextTreeLeafItem);
\ No newline at end of file
diff --git a/src/widget/formula/pane.function.js b/src/widget/formula/pane.function.js
new file mode 100644
index 000000000..fd02cb753
--- /dev/null
+++ b/src/widget/formula/pane.function.js
@@ -0,0 +1,175 @@
+/**
+ * Created by roy on 15/9/14.
+ */
+BI.FunctionPane = BI.inherit(BI.Widget, {
+    constants: {
+        search_height: 20,
+        height: 200,
+        width: 370,
+        column_size_editor: 170,
+        column_size_right: 200,
+        row_size: 30,
+        hgap: 10,
+        vgap: 10,
+        hgap_offset: 5
+    },
+    _defaultConfig: function () {
+        var conf = BI.FunctionPane.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: "bi-formula-function-pane",
+            width: 320,
+            height: 200,
+            items: []
+        })
+    },
+    _init: function () {
+        BI.FunctionPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this.constants;
+
+
+        this.desLabel = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "normal",
+            textWidth: 180
+        });
+
+        this.searchFunctionTree = BI.createWidget({
+            type: "bi.function_tree",
+            cls: "style-top",
+            redmark: function (val, ob) {
+                return true
+            }
+        });
+
+        this.functiontree = BI.createWidget({
+            type: "bi.function_tree",
+            cls: "style-top",
+            items: o.items
+        });
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            adapter: this.functiontree,
+            isAutoSearch: false,
+            onSearch: function (op, populate) {
+                var keyword = op.keyword.toLowerCase();
+                var resultArray = [];
+                BI.each(o.items, function (i, item) {
+                    if (item.value.toLowerCase().indexOf(keyword) > -1 && !BI.isEmptyString(keyword)) {
+                        resultArray.push(item);
+                    }
+                });
+                populate(resultArray, keyword);
+            },
+            el: {
+                type: "bi.small_search_editor"
+            },
+            popup: {
+                type: "bi.function_searcher_pane",
+                searcher: self.searchFunctionTree
+            },
+            height: 25,
+            width: 160
+        });
+
+
+        this.functionLabel = BI.createWidget({
+            type: "bi.label"
+        });
+
+        BI.createWidget({
+            element: this,
+            type: "bi.window",
+            width: c.width,
+            cls: "style-out",
+            columns: 2,
+            rows: 2,
+            columnSize: [c.column_size_editor, c.column_size_right],
+            rowSize: [c.row_size, 'fill'],
+            items: [
+                [
+                    {
+
+                        el: {
+                            type: "bi.center_adapt",
+                            hgap: c.hgap_offset,
+                            items: [
+                                {
+                                    el: self.searcher
+                                }
+                            ]
+
+
+                        }
+                    },
+                    {
+                        el: {
+                            type: "bi.center_adapt",
+                            cls: "style-left",
+                            items: [
+                                {
+                                    type: "bi.left",
+                                    hgap: c.hgap,
+                                    items: [
+                                        {
+                                            el: self.functionLabel
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    }
+                ], [
+                    {
+                        el: self.functiontree
+                    },
+                    {
+                        el: {
+                            type: "bi.absolute",
+                            cls: "style-inner",
+                            items: [
+                                {
+                                    el: self.desLabel,
+                                    left: c.hgap,
+                                    right: c.hgap,
+                                    top: c.hgap,
+                                    bottom: c.hgap
+                                }
+                            ]
+                        }
+                    }
+                ]
+            ]
+        });
+
+        self.functiontree.on(BI.FunctionTree.FUNCTION_INSERT, function (value) {
+            self.fireEvent(BI.FunctionPane.EVENT_INSET, value)
+        });
+
+        self.functiontree.on(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, function (v) {
+            self.desLabel.setText(v);
+        });
+
+        self.functiontree.on(BI.FunctionTree.EVENT_CHANGE, function (v) {
+            self.functionLabel.setText(v);
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.FUNCTION_INSERT, function (value) {
+            self.fireEvent(BI.FunctionPane.EVENT_INSET, value)
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, function (v) {
+            self.desLabel.setText(v);
+        });
+
+        self.searchFunctionTree.on(BI.FunctionTree.EVENT_CHANGE, function (v) {
+            self.functionLabel.setText(v);
+        });
+
+    }
+
+});
+BI.FunctionPane.EVENT_INSET = "EVENT_INSET";
+$.shortcut("bi.function_pane", BI.FunctionPane);
\ No newline at end of file
diff --git a/src/widget/formula/pane.searcher.function.js b/src/widget/formula/pane.searcher.function.js
new file mode 100644
index 000000000..1f2dcb343
--- /dev/null
+++ b/src/widget/formula/pane.searcher.function.js
@@ -0,0 +1,26 @@
+/**
+ * Created by roy on 16/1/21.
+ */
+BI.FunctionSearcherPane = BI.inherit(BI.SearcherView, {
+    _defaultConfig: function () {
+        var conf = BI.FunctionSearcherPane.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-function-searcher-pane"
+        })
+    },
+
+    _init: function () {
+        BI.FunctionSearcherPane.superclass._init.apply(this, arguments);
+    },
+
+    populate: function (searchResult, keyword) {
+        searchResult || (searchResult = []);
+        this.spliter.setVisible(false);
+        this.searcher.populate(searchResult, keyword);
+        this.searcher.expandAll();
+        this.searcher.doBehavior(keyword);
+    },
+
+
+});
+$.shortcut("bi.function_searcher_pane", BI.FunctionSearcherPane);
\ No newline at end of file
diff --git a/src/widget/formula/tree.fieldname.js b/src/widget/formula/tree.fieldname.js
new file mode 100644
index 000000000..d22b61435
--- /dev/null
+++ b/src/widget/formula/tree.fieldname.js
@@ -0,0 +1,110 @@
+BI.FormulaFieldTree = BI.inherit(BI.Widget, {
+    _const: {
+        leafGap: 40
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FormulaFieldTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-field-tree",
+            chooseType: 0,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.FormulaFieldTree.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getFieldNum: function (map, fieldtype) {
+        if (BI.isNotNull(map[fieldtype])) {
+            return map[fieldtype].length
+        } else {
+            return 0
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options, c = this._const, self = this;
+        this.empty();
+        var map = {};
+        BI.each(items, function (i, typeItem) {
+            BI.each(typeItem, function (i, item) {
+                if (!map[item.fieldType]) {
+                    map[item.fieldType] = [];
+                }
+                map[item.fieldType].push(item);
+            })
+        });
+
+        var nodes = [{
+            id: BICst.COLUMN.NUMBER,
+            type: "bi.triangle_group_node",
+            text: BI.i18nText("BI-Formula_Numberic_Field") + "(" + self._getFieldNum(map,BICst.COLUMN.NUMBER) + ")",
+            value: BICst.COLUMN.NUMBER,
+            isParent: true,
+            open: items.length === 1
+        }];
+
+        if(items.length > 1){
+            nodes.push({
+                id: BICst.COLUMN.STRING,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Text_Field") + "(" + self._getFieldNum(map, BICst.COLUMN.STRING) + ")",
+                value: BICst.COLUMN.STRING,
+                isParent: true,
+                open: false
+            });
+        }
+
+        if(items.length > 2){
+            nodes.push({
+                id: BICst.COLUMN.DATE,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Time_Field") + "(" + self._getFieldNum(map, BICst.COLUMN.DATE) + ")",
+                value: BICst.COLUMN.DATE,
+                isParent: true,
+                open: false
+            });
+        }
+
+        BI.each(items, function(idx, typeItems){
+            BI.each(typeItems, function (i, item) {
+                nodes.push(BI.extend({
+                    id: BI.UUID(),
+                    pId: item.fieldType
+                }, item, {
+                    type: "bi.tree_text_leaf_item",
+                    cls: "tree-text-leaf-item-draggable",
+                    textAlign: "left",
+                    lgap: c.leafGap
+                }))
+            });
+        });
+        this.fieldtree = BI.createWidget({
+            type: "bi.level_tree",
+            element: this,
+            chooseType: o.chooseType,
+            expander: {
+                isDefaultInit: true
+            },
+            items: nodes
+        });
+        this.fieldtree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FormulaFieldTree.EVENT_CHANGE);
+            self.fieldtree.setValue();
+        })
+    },
+
+    getValue: function () {
+        return this.fieldtree.getValue();
+    },
+
+    setValue: function (v) {
+        this.fieldtree.setValue(v);
+    },
+    getAllLeaves: function () {
+        return this.fieldtree.getAllLeaves()
+    }
+});
+BI.FormulaFieldTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.formula_field_tree", BI.FormulaFieldTree);
\ No newline at end of file
diff --git a/src/widget/formula/tree.function.js b/src/widget/formula/tree.function.js
new file mode 100644
index 000000000..a34f9d4ef
--- /dev/null
+++ b/src/widget/formula/tree.function.js
@@ -0,0 +1,170 @@
+/**
+ * Created by roy on 15/9/14.
+ */
+BI.FunctionTree = BI.inherit(BI.Widget, {
+    _const: {
+        leafGap: 10,
+        nodeTypes: [BICst.FUNCTION.MATH, BICst.FUNCTION.ARRAY, BICst.FUNCTION.DATE, BICst.FUNCTION.LOGIC, BICst.FUNCTION.OTHER, BICst.FUNCTION.TEXT]
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.FunctionTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-formula-function-tree",
+            chooseType: 0,
+            items: [],
+            redmark: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.FunctionTree.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _getFieldNum: function (map, fieldtype) {
+        if (BI.isNotNull(map[fieldtype])) {
+            return map[fieldtype].length
+        } else {
+            return 0
+        }
+    },
+
+    populate: function (items) {
+        var o = this.options, c = this._const, self = this;
+        this.empty();
+        var map = {};
+        o.items = items;
+        BI.each(items, function (i, item) {
+            if (!map[item.fieldType]) {
+                map[item.fieldType] = [];
+            }
+            map[item.fieldType].push(item);
+        });
+        this.nodes = [
+            {
+                id: BICst.FUNCTION.MATH,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Numberic_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.MATH) + ")",
+                value: BICst.FUNCTION.MATH,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.TEXT,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Text_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.TEXT) + ")",
+                value: BICst.FUNCTION.TEXT,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.DATE,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Time_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.DATE) + ")",
+                value: BICst.FUNCTION.DATE,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.ARRAY,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Array_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.ARRAY) + ")",
+                value: BICst.FUNCTION.ARRAY,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.LOGIC,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Logic_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.LOGIC) + ")",
+                value: BICst.FUNCTION.LOGIC,
+                isParent: true,
+                open: false
+            }, {
+                id: BICst.FUNCTION.OTHER,
+                type: "bi.triangle_group_node",
+                text: BI.i18nText("BI-Formula_Other_Function") + "(" + self._getFieldNum(map, BICst.FUNCTION.OTHER) + ")",
+                value: BICst.FUNCTION.OTHER,
+                isParent: true,
+                open: false
+            }
+        ];
+        BI.each(items, function (i, item) {
+            self.nodes.push(BI.extend({
+                id: BI.UUID(),
+                pId: item.fieldType
+            }, item, {
+                type: "bi.button_text_tree_leaf_item",
+                textAlign: "left",
+                lgap: c.leafGap
+            }))
+        });
+        this.fieldtree = BI.createWidget({
+            type: "bi.level_tree",
+            element: this,
+            items: self.nodes,
+            el: {
+                behaviors: {
+                    "redmark": o.redmark
+                }
+            }
+        });
+
+        this.fieldtree.on(BI.Controller.EVENT_CHANGE, function (type, value) {
+            if (type === BI.Events.ADD) {
+                self.fireEvent(BI.FunctionTree.FUNCTION_INSERT, value);
+            }
+        });
+        this.fieldtree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.FunctionTree.EVENT_CHANGE, self.getValue());
+            self.fireEvent(BI.FunctionTree.EVENT_DESCRIPTION_CHANGE, self._getDescription(self.getValue(), o.items))
+            self.fieldtree.setValue(self.getValue());
+        })
+    },
+
+    getValue: function () {
+        return this.fieldtree.getValue();
+    },
+
+    setValue: function (v) {
+        this.fieldtree.setValue(v);
+    },
+
+    doBehavior: function () {
+        this.fieldtree.doBehavior.apply(this.fieldtree, arguments)
+    },
+
+    getNodeByValue: function (v) {
+        return this.fieldtree.getNodeByValue(v)
+    },
+
+    setTriggerExpand: function (v) {
+        var node = this.fieldtree.getNodeById(v);
+        node.showView();
+    },
+
+    setTriggerCollapse: function (v) {
+        var node = this.fieldtree.getNodeById(v);
+        node.hideView();
+    },
+
+    expandAll: function () {
+        var self = this;
+        BI.each(self._const.nodeTypes, function (i, id) {
+            self.setTriggerExpand(id);
+        })
+    },
+
+    _getDescription: function (v, items) {
+        var description = "";
+        BI.each(items, function (i, item) {
+            if (item.value === v[0]) {
+                description = item.description;
+            }
+        });
+        return description
+    },
+
+    getAllLeaves: function () {
+        return this.fieldtree.getAllLeaves()
+    }
+});
+BI.FunctionTree.EVENT_CHANGE = "EVENT_CHANGE";
+BI.FunctionTree.EVENT_DESCRIPTION_CHANGE = "EVENT_DESCRIPTION_CHANGE";
+BI.FunctionTree.FUNCTION_INSERT = "FUNCTION_INSERT";
+$.shortcut("bi.function_tree", BI.FunctionTree);
\ No newline at end of file
diff --git a/src/widget/image/button/href/image.button.href.js b/src/widget/image/button/href/image.button.href.js
new file mode 100644
index 000000000..2120c32ec
--- /dev/null
+++ b/src/widget/image/button/href/image.button.href.js
@@ -0,0 +1,77 @@
+/**
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonHref = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ImageButtonHref.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-image-button-href",
+            title: BI.i18nText("BI-Add_Href")
+        })
+    },
+
+    _init: function () {
+        BI.ImageButtonHref.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "img-href-font",
+            title: o.title,
+            height: 24,
+            width: 24
+        });
+
+        this.input = BI.createWidget({
+            type: "bi.clear_editor",
+            watermark: BI.i18nText("BI-Input_Href"),
+            width: 255,
+            height: 30
+        });
+        this.input.on(BI.ClearEditor.EVENT_CONFIRM, function () {
+            self.combo.hideView();
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            direction: "bottom,left",
+            adjustYOffset: 3,
+            el: this.trigger,
+            popup: {
+                el: this.input,
+                stopPropagation: false,
+                minWidth: 255
+            }
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () {
+            self.input.focus()
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () {
+            self.fireEvent(BI.ImageButtonHref.EVENT_CHANGE, arguments)
+        })
+    },
+
+    isSelected: function(){
+        return this.combo.isViewVisible();
+    },
+
+    showView: function(){
+        this.combo.showView();
+    },
+
+    hideView: function () {
+        this.combo.hideView();
+    },
+
+    getValue: function () {
+        return this.input.getValue();
+    },
+
+    setValue: function (url) {
+        this.input.setValue(url)
+    }
+});
+BI.ImageButtonHref.EVENT_CHANGE = "BI.ImageButtonHref.EVENT_CHANGE";
+$.shortcut("bi.image_button_href", BI.ImageButtonHref);
\ No newline at end of file
diff --git a/src/widget/image/button/size/image.button.size.combo.js b/src/widget/image/button/size/image.button.size.combo.js
new file mode 100644
index 000000000..e3ffd8cfb
--- /dev/null
+++ b/src/widget/image/button/size/image.button.size.combo.js
@@ -0,0 +1,55 @@
+/**
+ * 图片尺寸控件
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSizeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ImageButtonSizeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-image-button-size-combo",
+            title: BI.i18nText("BI-Image_Size")
+        })
+    },
+
+    _init: function () {
+        BI.ImageButtonSizeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "img-size-font",
+            title: o.title,
+            width: 24,
+            height: 24
+        });
+        this.sizeChooser = BI.createWidget({
+            type: "bi.image_button_size"
+        });
+        this.sizeChooser.on(BI.ImageButtonSize.EVENT_CHANGE, function(){
+            self.fireEvent(BI.ImageButtonSizeCombo.EVENT_CHANGE,arguments)
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustWidth: false,
+            direction: "top",
+            adjustYOffset: 3,
+            offsetStyle: "right",
+            el: this.trigger,
+            popup: {
+                el: this.sizeChooser,
+                stopPropagation: false
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.sizeChooser.setValue(v);
+    },
+
+    getValue: function () {
+        return this.sizeChooser.getValue();
+    }
+});
+BI.ImageButtonSizeCombo.EVENT_CHANGE = "ImageButtonSizeCombo.EVENT_CHANGE";
+$.shortcut("bi.image_button_size_combo", BI.ImageButtonSizeCombo);
\ No newline at end of file
diff --git a/src/widget/image/button/size/image.button.size.js b/src/widget/image/button/size/image.button.size.js
new file mode 100644
index 000000000..db8c168e7
--- /dev/null
+++ b/src/widget/image/button/size/image.button.size.js
@@ -0,0 +1,71 @@
+/**
+ * 单选框
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSize = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function(){
+        return BI.extend(BI.ImageButtonSize.superclass._defaultConfig.apply(this, arguments),{
+            baseCls: "bi-image-button-size",
+            width: 230,
+            height: 30
+        })
+    },
+
+    _init:function() {
+        BI.ImageButtonSize.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.sizeChooser = BI.createWidget({
+            type: "bi.button_group",
+            scrollable: false,
+            items: BI.createItems([{
+                text: BI.i18nText("BI-Original_Size"),
+                cls: "image-button-size-button-group",
+                width: 55,
+                selected: true,
+                value: BICst.IMAGE_RESIZE_MODE.ORIGINAL
+            },{
+                text: BI.i18nText("BI-Equal_Size_Adapt"),
+                cls: "image-button-size-button-group",
+                width: 67,
+                value: BICst.IMAGE_RESIZE_MODE.EQUAL
+            },{
+                text: BI.i18nText("BI-Widget_Size_Adapt"),
+                cls: "image-button-size-button-group",
+                width: 67,
+                value: BICst.IMAGE_RESIZE_MODE.STRETCH
+            }],{
+                type: "bi.image_button_size_radio"
+            }),
+            layouts: [{
+                type: "bi.left",
+                hgap: 5
+            }]
+        });
+
+        this.sizeChooser.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.sizeChooser.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.ImageButtonSize.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.sizeChooser],
+            hgap: 5
+        });
+        this.getValue()
+    },
+
+    getValue: function () {
+        return this.sizeChooser.getValue()[0]
+    },
+
+    setValue: function (v) {
+        this.sizeChooser.setValue(v)
+    }
+});
+BI.ImageButtonSize.EVENT_CHANGE = "BI.ImageButtonSize.EVENT_CHANGE";
+$.shortcut("bi.image_button_size" , BI.ImageButtonSize);
\ No newline at end of file
diff --git a/src/widget/image/button/size/radio/image.button.size.radio.js b/src/widget/image/button/size/radio/image.button.size.radio.js
new file mode 100644
index 000000000..98011b35f
--- /dev/null
+++ b/src/widget/image/button/size/radio/image.button.size.radio.js
@@ -0,0 +1,66 @@
+/**
+ * 单选框
+ * Created by GameJian on 2016/1/28.
+ */
+BI.ImageButtonSizeRadio = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function(){
+        return BI.extend(BI.ImageButtonSizeRadio.superclass._defaultConfig.apply(this, arguments),{
+            width: 65,
+            height: 30,
+            text: "",
+            selected: false
+        })
+    },
+
+    _init:function() {
+        BI.ImageButtonSizeRadio.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: o.selected
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            lgap: 5,
+            rgap: 0,
+            textHeight: o.height,
+            height: o.height,
+            text: o.text
+        });
+
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(!self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            element: this,
+            type: "bi.absolute",
+            items: [{
+                el: this.radio,
+                left: 0,
+                top: 8.5
+            },{
+                el: this.label,
+                left: 13
+            }]
+        });
+    },
+
+    doClick: function () {
+        BI.ImageButtonSizeRadio.superclass.doClick.apply(this, arguments);
+        this.radio.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.ImageButtonSizeRadio.superclass.setSelected.apply(this, arguments);
+        this.radio.setSelected(v);
+
+    }
+});
+$.shortcut("bi.image_button_size_radio" , BI.ImageButtonSizeRadio);
\ No newline at end of file
diff --git a/src/widget/image/uploadimage.js b/src/widget/image/uploadimage.js
new file mode 100644
index 000000000..c9ca03231
--- /dev/null
+++ b/src/widget/image/uploadimage.js
@@ -0,0 +1,277 @@
+/**
+ * 图片组件
+ * Created by GameJian on 2016/1/26.
+ */
+BI.UploadImage = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.UploadImage.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-upload-image"
+        })
+    },
+
+    _init: function () {
+        BI.UploadImage.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.label = BI.createWidget({
+            type: "bi.text_button",
+            trigger: "dblclick",
+            cls: "upload-image-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-DoubleClick_To_Upload_Image")
+        });
+
+        this.file = BI.createWidget({
+            type: "bi.multifile_editor",
+            accept: "*.jpg;*.png;*.gif;*.bmp;*.jpeg;",
+            maxSize: 1024 * 1024 * 100,
+            title: BI.i18nText("BI-Upload_Image")
+        });
+
+        this.img = BI.createWidget({
+            type: "bi.image_button",
+            invalid: true,
+            width: "100%",
+            height: "100%"
+        });
+
+        this.label.on(BI.TextButton.EVENT_CHANGE, function () {
+            if (self.isValid()) {
+                self.file.select();
+            }
+        });
+
+        this.file.on(BI.MultifileEditor.EVENT_CHANGE, function (data) {
+            this.upload();
+        });
+        //直接把图片保存到resource目录下面
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADED, function () {
+            var files = this.getValue();
+            var file = files[files.length - 1];
+            var attachId = file.attach_id, fileName = file.filename;
+            var imageId = attachId + "_" + fileName;
+            BI.requestAsync("fr_bi_base", "save_upload_image", {
+                attach_id: attachId
+            }, function (res) {
+                self.img.setValue(imageId);
+                self.img.setSrc(BI.UploadImage.getImageSrc(imageId));
+                self._check();
+                self._setSize("auto", "auto");
+                self.fireEvent(BI.UploadImage.EVENT_CHANGE, imageId);
+            })
+        });
+
+        this.uploadWrapper = BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "upload-image-icon-button img-upload-font",
+                    width: 24,
+                    height: 24
+                },
+                top: 0,
+                right: 0,
+                bottom: 0,
+                left: 0
+            }, {
+                el: this.file,
+                top: 0,
+                right: 0,
+                bottom: 0,
+                left: 0
+            }],
+            width: 24,
+            height: 24
+        });
+
+        this.del = BI.createWidget({
+            type: "bi.bubble_combo",
+            el: {
+                type: "bi.icon_button",
+                cls: "upload-image-icon-button img-shutdown-font",
+                title: BI.i18nText("BI-Basic_Delete"),
+                height: 24,
+                width: 24
+            },
+            popup: {
+                type: "bi.bubble_bar_popup_view",
+                buttons: [{
+                    value: BI.i18nText(BI.i18nText("BI-Basic_Sure")),
+                    handler: function () {
+                        self.fireEvent(BI.UploadImage.EVENT_DESTROY);
+                    }
+                }, {
+                    value: BI.i18nText("BI-Basic_Cancel"),
+                    level: "ignore",
+                    handler: function () {
+                        self.del.hideView();
+                    }
+                }],
+                el: {
+                    type: "bi.vertical_adapt",
+                    items: [{
+                        type: "bi.label",
+                        text: BI.i18nText("BI-Sure_Delete_Current_Component"),
+                        cls: "upload-image-delete-label",
+                        textAlign: "left",
+                        width: 300
+                    }],
+                    width: 300,
+                    height: 100,
+                    hgap: 20
+                },
+                maxHeight: 140,
+                minWidth: 340
+            },
+            invisible: true,
+            stopPropagation: true
+        });
+
+        this.size = BI.createWidget({
+            type: "bi.image_button_size_combo",
+            cls: "upload-image-icon-button"
+        });
+
+        this.size.on(BI.ImageButtonSizeCombo.EVENT_CHANGE, function () {
+            self._sizeChange(self.size.getValue());
+            self.fireEvent(BI.UploadImage.EVENT_CHANGE, arguments)
+        });
+
+        this.href = BI.createWidget({
+            type: "bi.image_button_href",
+            cls: "upload-image-icon-button"
+        });
+
+        this.href.on(BI.ImageButtonHref.EVENT_CHANGE, function () {
+            if (BI.isNotEmptyString(self.href.getValue())) {
+                self.img.setValid(true)
+            } else {
+                self.img.setValid(false)
+            }
+            self.fireEvent(BI.UploadImage.EVENT_CHANGE, arguments)
+        });
+
+        this.img.on(BI.ImageButton.EVENT_CHANGE, function () {
+            window.open(BI.Func.formatAddress(self.href.getValue()));
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    scrollable: false,
+                    items: [{
+                        el: this.img
+                    }]
+                },
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: this.label,
+                left: 10,
+                right: 10,
+                top: 10,
+                bottom: 10
+            }, {
+                el: this.del,
+                right: 4,
+                top: 8
+            }, {
+                el: this.href,
+                right: 36,
+                top: 8
+            }, {
+                el: this.size,
+                right: 68,
+                top: 8
+            }, {
+                el: this.uploadWrapper,
+                right: 100,
+                top: 8
+            }]
+        });
+
+        this.setToolbarVisible(false);
+        this.img.invisible();
+    },
+
+    _check: function () {
+        var f = BI.isNotEmptyString(this.img.getValue());
+        this.label.setVisible(!f);
+        this.img.visible(f);
+    },
+
+    _setSize: function (w, h) {
+        this.img.setImageWidth(w);
+        this.img.setImageHeight(h)
+    },
+
+    _sizeChange: function (size) {
+        var self = this, o = this.options;
+        switch (size) {
+            case BICst.IMAGE_RESIZE_MODE.ORIGINAL:
+                self._setSize("auto", "auto");
+                break;
+            case BICst.IMAGE_RESIZE_MODE.EQUAL:
+                self._setSize("auto", "auto");
+                var width = this.img.getImageWidth(), height = this.img.getImageHeight();
+                var W = this.element.width(), H = this.element.height();
+                if (W / H > width / height) {
+                    self._setSize("auto", "100%");
+                } else {
+                    self._setSize("100%", "auto");
+                }
+                break;
+            case BICst.IMAGE_RESIZE_MODE.STRETCH:
+                self._setSize("100%", "100%");
+                break;
+            default :
+                self._setSize("auto", "auto");
+        }
+    },
+
+    setToolbarVisible: function (v) {
+        this.uploadWrapper.setVisible(v);
+        this.size.setVisible(v);
+        this.href.setVisible(v);
+        this.del.setVisible(v);
+    },
+
+    getValue: function () {
+        return {href: this.href.getValue(), size: this.size.getValue(), src: this.img.getValue()}
+    },
+
+    setValue: function (v) {
+        var self = this;
+        v || (v = {});
+        if (BI.isNotEmptyString(v.href)) {
+            self.img.setValid(true)
+        }
+        this.href.setValue(v.href);
+        this.size.setValue(v.size);
+        this.img.setValue(v.src);
+        if (BI.isNotEmptyString(v.src)) {
+            this.img.setSrc(BI.UploadImage.getImageSrc(v.src));
+        }
+        this._check();
+        this._sizeChange(v.size)
+    },
+
+    resize: function () {
+        this._sizeChange(this.size.getValue());
+    }
+});
+
+BI.extend(BI.UploadImage, {
+    getImageSrc: function (src) {
+        return FR.servletURL + "?op=fr_bi&cmd=get_uploaded_image&image_id=" + src;
+    }
+});
+
+BI.UploadImage.EVENT_DESTROY = "EVENT_DESTROY";
+BI.UploadImage.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.upload_image", BI.UploadImage);
\ No newline at end of file
diff --git a/src/widget/interactivearrangement/interactivearrangement.js b/src/widget/interactivearrangement/interactivearrangement.js
new file mode 100644
index 000000000..7a32a545c
--- /dev/null
+++ b/src/widget/interactivearrangement/interactivearrangement.js
@@ -0,0 +1,571 @@
+/**
+ * 交互行为布局
+ *
+ *
+ * Created by GUY on 2016/7/23.
+ * @class BI.InteractiveArrangement
+ * @extends BI.Widget
+ */
+BI.InteractiveArrangement = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.InteractiveArrangement.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-interactive-arrangement",
+            resizable: true,
+            isNeedReLayout: true,
+            isNeedResizeContainer: true,
+            layoutType: BI.Arrangement.LAYOUT_TYPE.FREE,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.InteractiveArrangement.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.arrangement = BI.createWidget({
+            type: "bi.adaptive_arrangement",
+            element: this,
+            resizable: o.resizable,
+            isNeedReLayout: o.isNeedReLayout,
+            isNeedResizeContainer: o.isNeedResizeContainer,
+            layoutType: o.layoutType,
+            items: o.items
+        });
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_RESIZE, function () {
+            self.fireEvent(BI.InteractiveArrangement.EVENT_RESIZE, arguments);
+        });
+
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, function (id, size) {
+            var p = self._getRegionClientPosition(id);
+            self.draw({
+                left: p.left,
+                top: p.top
+            }, size, id);
+        });
+        this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, function (id, size) {
+            self.stopDraw();
+            self.setRegionSize(id, size);
+        });
+
+        this.tags = [];
+
+    },
+
+    _isEqual: function (num1, num2) {
+        return this.arrangement._isEqual(num1, num2);
+    },
+
+    _getScrollOffset: function () {
+        return this.arrangement._getScrollOffset();
+    },
+
+    _positionAt: function (position, regions) {
+        var self = this;
+        regions = regions || this.getAllRegions();
+        var left = [], center = [], right = [], top = [], middle = [], bottom = [];
+        BI.each(regions, function (i, region) {
+            var client = self._getRegionClientPosition(region.id);
+            if (Math.abs(client.left - position.left) <= 3) {
+                left.push(region);
+            }
+            if (Math.abs(client.left + client.width / 2 - position.left) <= 3) {
+                center.push(region);
+            }
+            if (Math.abs(client.left + client.width - position.left) <= 3) {
+                right.push(region);
+            }
+            if (Math.abs(client.top - position.top) <= 3) {
+                top.push(region);
+            }
+            if (Math.abs(client.top + client.height / 2 - position.top) <= 3) {
+                middle.push(region);
+            }
+            if (Math.abs(client.top + client.height - position.top) <= 3) {
+                bottom.push(region);
+            }
+        });
+        return {
+            left: left,
+            center: center,
+            right: right,
+            top: top,
+            middle: middle,
+            bottom: bottom
+        }
+    },
+
+    _getRegionClientPosition: function (name) {
+        var region = this.getRegionByName(name);
+        var offset = this.arrangement._getScrollOffset();
+        return {
+            top: region.top - offset.top,
+            left: region.left - offset.left,
+            width: region.width,
+            height: region.height,
+            id: region.id
+        }
+    },
+
+    _vAlign: function (position, regions) {
+        var self = this;
+        var vs = this._positionAt(position, regions);
+        var positions = [];
+        var l;
+        if (vs.left.length > 0) {
+            l = this._getRegionClientPosition(vs.left[0].id).left;
+        } else if (vs.right.length > 0) {
+            var temp = this._getRegionClientPosition(vs.right[0].id);
+            l = temp.left + temp.width;
+        }
+        var rs = vs.left.concat(vs.right);
+        BI.each(rs, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.left, l) || self._isEqual(p.left + p.width, l)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: l
+                };
+                positions.push({
+                    id: region.id,
+                    start: topPoint,
+                    end: {
+                        left: l,
+                        top: position.top
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _leftAlign: function (position, size, regions) {
+        var self = this;
+        return this._vAlign({
+            left: position.left,
+            top: position.top + size.height / 2
+        }, regions);
+    },
+
+    _rightAlign: function (position, size, regions) {
+        var self = this;
+        return this._vAlign({
+            left: position.left + size.width,
+            top: position.top + size.height / 2
+        }, regions);
+    },
+
+    _hAlign: function (position, regions) {
+        var self = this;
+        var hs = this._positionAt(position, regions);
+        var positions = [];
+        var t;
+        if (hs.top.length > 0) {
+            var temp = this._getRegionClientPosition(hs.top[0].id);
+            t = temp.top;
+        } else if (hs.bottom.length > 0) {
+            var temp = this._getRegionClientPosition(hs.bottom[0].id);
+            t = temp.top + temp.height;
+        }
+        var rs = hs.top.concat(hs.bottom);
+        BI.each(rs, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.top, t) || self._isEqual(p.top + p.height, t)) {
+                var leftPoint = {
+                    top: t,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: leftPoint,
+                    end: {
+                        left: position.left,
+                        top: t
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _topAlign: function (position, size, regions) {
+        var self = this;
+        return this._hAlign({
+            left: position.left + size.width / 2,
+            top: position.top
+        }, regions);
+    },
+
+    _bottomAlign: function (position, size, regions) {
+        var self = this;
+        return this._hAlign({
+            left: position.left + size.width / 2,
+            top: position.top + size.height
+        }, regions);
+    },
+
+    _centerAlign: function (position, size, regions) {
+        var self = this;
+        var cs = this._positionAt({
+            left: position.left + size.width / 2,
+            top: position.top + size.height / 2
+        }, regions);
+        var positions = [];
+        var l;
+        if (cs.center.length > 0) {
+            var temp = this._getRegionClientPosition(cs.center[0].id);
+            l = temp.left + temp.width / 2;
+        }
+        BI.each(cs.center, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.left + p.width / 2, l)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: topPoint,
+                    end: {
+                        left: l,
+                        top: position.top + size.height / 2
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+    _middleAlign: function (position, size, regions) {
+        var self = this;
+        var cs = this._positionAt({
+            left: position.left + size.width / 2,
+            top: position.top + size.height / 2
+        }, regions);
+        var positions = [];
+        var t;
+        if (cs.middle.length > 0) {
+            var temp = this._getRegionClientPosition(cs.middle[0].id);
+            t = temp.top + temp.height / 2;
+        }
+        BI.each(cs.middle, function (i, region) {
+            var p = self._getRegionClientPosition(region.id);
+            if (self._isEqual(p.top + p.height / 2, t)) {
+                var topPoint = {
+                    top: p.top + p.height / 2,
+                    left: p.left + p.width / 2
+                };
+                positions.push({
+                    id: p.id,
+                    start: topPoint,
+                    end: {
+                        left: position.left + size.width / 2,
+                        top: t
+                    }
+                });
+            }
+        });
+        return positions;
+    },
+
+
+    _drawOneTag: function (start, end) {
+        var s = BI.createWidget({
+            type: "bi.icon_button",
+            //invisible: true,
+            width: 13,
+            height: 13,
+            cls: "drag-tag-font interactive-arrangement-dragtag-icon"
+        });
+        var e = BI.createWidget({
+            type: "bi.icon_button",
+            //invisible: true,
+            width: 13,
+            height: 13,
+            cls: "drag-tag-font interactive-arrangement-dragtag-icon"
+        });
+        if (this._isEqual(start.left, end.left)) {
+            var line = BI.createWidget({
+                type: "bi.layout",
+                //invisible: true,
+                cls: "interactive-arrangement-dragtag-line",
+                width: 1,
+                height: Math.abs(start.top - end.top)
+            });
+        } else {
+            var line = BI.createWidget({
+                type: "bi.layout",
+                //invisible: true,
+                cls: "interactive-arrangement-dragtag-line",
+                height: 1,
+                width: Math.abs(start.left - end.left)
+            });
+        }
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: s,
+                left: start.left - 6,
+                top: start.top - 7
+            }, {
+                el: e,
+                left: end.left - 6,
+                top: end.top - 7
+            }, {
+                el: line,
+                left: Math.min(start.left, end.left),
+                top: Math.min(start.top, end.top)
+            }]
+        });
+        this.tags.push(s);
+        this.tags.push(e);
+        this.tags.push(line);
+    },
+
+    stopDraw: function () {
+        BI.each(this.tags, function (i, w) {
+            w.destroy();
+        });
+        this.tags = [];
+    },
+
+    _getRegionExcept: function (name, regions) {
+        var other = [];
+        BI.each(regions || this.getAllRegions(), function (i, region) {
+            if (!(name && region.id === name)) {
+                other.push(region);
+            }
+        });
+        return other;
+    },
+
+    getClientWidth: function () {
+        return this.arrangement.getClientWidth();
+    },
+
+    getClientHeight: function () {
+        return this.arrangement.getClientHeight();
+    },
+
+    getPosition: function (name, position, size) {
+        var regions = this.getAllRegions();
+        var me;
+        if (name) {
+            me = this._getRegionClientPosition(name);
+        }
+        var other = this._getRegionExcept(name, regions);
+        position = position || {
+                left: me.left,
+                top: me.top
+            };
+        size = size || {
+                width: me.width,
+                height: me.height
+            };
+        var left = this._leftAlign(position, size, other);
+        var right = this._rightAlign(position, size, other);
+        var top = this._topAlign(position, size, other, other);
+        var bottom = this._bottomAlign(position, size, other);
+        var center = this._centerAlign(position, size, other);
+        var middle = this._middleAlign(position, size, other);
+
+        BI.each(center, function (i, pos) {
+            position.left = pos.end.left - size.width / 2;
+        });
+        BI.each(right, function (i, pos) {
+            position.left = pos.end.left - size.width;
+        });
+        BI.each(left, function (i, pos) {
+            position.left = pos.end.left;
+        });
+        BI.each(middle, function (i, pos) {
+            position.top = pos.end.top - size.height / 2;
+        });
+        BI.each(bottom, function (i, pos) {
+            position.top = pos.end.top - size.height;
+        });
+        BI.each(top, function (i, pos) {
+            position.top = pos.end.top;
+        });
+        return position;
+    },
+
+    //position不动 变size
+    getSize: function (name, position, size) {
+        var regions = this.getAllRegions();
+        var me;
+        if (name) {
+            me = this._getRegionClientPosition(name);
+        }
+        var other = this._getRegionExcept(name, regions);
+        position = position || {
+                left: me.left,
+                top: me.top
+            };
+        size = size || {
+                width: me.width,
+                height: me.height
+            };
+        var left = this._leftAlign(position, size, other);
+        var right = this._rightAlign(position, size, other);
+        var top = this._topAlign(position, size, other, other);
+        var bottom = this._bottomAlign(position, size, other);
+        var center = this._centerAlign(position, size, other);
+        var middle = this._middleAlign(position, size, other);
+
+        BI.each(center, function (i, pos) {
+            size.width = (pos.end.left - position.left) * 2;
+        });
+        BI.each(right, function (i, pos) {
+            size.width = pos.end.left - position.left;
+        });
+        BI.each(left, function (i, pos) {
+        });
+        BI.each(middle, function (i, pos) {
+            size.height = (pos.end.top - position.top) * 2;
+        });
+        BI.each(bottom, function (i, pos) {
+            size.height = pos.end.top - position.top;
+        });
+        BI.each(top, function (i, pos) {
+        });
+        return size;
+    },
+
+    draw: function (position, size, name) {
+        var self = this;
+        this.stopDraw();
+        switch (this.getLayoutType()) {
+            case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+            case BI.Arrangement.LAYOUT_TYPE.FREE:
+                var other = this._getRegionExcept(name);
+                var left = this._leftAlign(position, size, other);
+                var right = this._rightAlign(position, size, other);
+                var top = this._topAlign(position, size, other);
+                var bottom = this._bottomAlign(position, size, other);
+                var center = this._centerAlign(position, size, other);
+                var middle = this._middleAlign(position, size, other);
+
+                BI.each(center, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(right, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(left, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(middle, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(bottom, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                BI.each(top, function (i, pos) {
+                    self._drawOneTag(pos.start, pos.end);
+                });
+                break;
+            case BI.Arrangement.LAYOUT_TYPE.GRID:
+                break;
+        }
+    },
+
+    getDirectRelativeRegions: function (name, direction) {
+        return this.arrangement.getDirectRelativeRegions(name, direction);
+    },
+
+    addRegion: function (region, position) {
+        this.stopDraw();
+        return this.arrangement.addRegion(region, position);
+    },
+
+    deleteRegion: function (name) {
+        return this.arrangement.deleteRegion(name);
+    },
+
+    setRegionSize: function (name, size) {
+        size = this.getSize(name, null, size);
+        return this.arrangement.setRegionSize(name, size);
+    },
+
+    setPosition: function (position, size) {
+        var self = this;
+        this.stopDraw();
+        if (position.left > 0 && position.top > 0) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    position = this.getPosition(null, position, size);
+                    this.draw(position, size);
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        var at = this.arrangement.setPosition(position, size);
+        return at;
+    },
+
+    setRegionPosition: function (name, position) {
+        if (position.left > 0 && position.top > 0) {
+            switch (this.getLayoutType()) {
+                case BI.Arrangement.LAYOUT_TYPE.ADAPTIVE:
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.FREE:
+                    position = this.getPosition(name, position);
+                    break;
+                case BI.Arrangement.LAYOUT_TYPE.GRID:
+                    break;
+            }
+        }
+        return this.arrangement.setRegionPosition(name, position);
+    },
+
+    zoom: function (ratio) {
+        this.arrangement.zoom(ratio);
+    },
+
+    resize: function () {
+        return this.arrangement.resize();
+    },
+
+    relayout: function () {
+        return this.arrangement.relayout();
+    },
+
+    setLayoutType: function (type) {
+        this.arrangement.setLayoutType(type);
+    },
+
+    getLayoutType: function () {
+        return this.arrangement.getLayoutType();
+    },
+
+    getLayoutRatio: function () {
+        return this.arrangement.getLayoutRatio();
+    },
+
+    getHelper: function () {
+        return this.arrangement.getHelper();
+    },
+
+    getRegionByName: function (name) {
+        return this.arrangement.getRegionByName(name);
+    },
+
+    getAllRegions: function () {
+        return this.arrangement.getAllRegions();
+    },
+
+    revoke: function () {
+        return this.arrangement.revoke();
+    },
+
+    populate: function (items) {
+        var self = this;
+        this.arrangement.populate(items);
+    }
+});
+BI.InteractiveArrangement.EVENT_RESIZE = "InteractiveArrangement.EVENT_RESIZE";
+$.shortcut('bi.interactive_arrangement', BI.InteractiveArrangement);
\ No newline at end of file
diff --git a/src/widget/intervalslider/intervalslider.js b/src/widget/intervalslider/intervalslider.js
new file mode 100644
index 000000000..dcae95d42
--- /dev/null
+++ b/src/widget/intervalslider/intervalslider.js
@@ -0,0 +1,437 @@
+/**
+ * Created by zcf on 2016/9/26.
+ */
+BI.IntervalSlider = BI.inherit(BI.Widget, {
+    _constant: {
+        EDITOR_WIDTH: 90,
+        EDITOR_HEIGHT: 30,
+        HEIGHT: 28,
+        SLIDER_WIDTH_HALF: 15,
+        SLIDER_WIDTH: 30,
+        SLIDER_HEIGHT: 30,
+        TRACK_HEIGHT: 24
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.IntervalSlider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider bi-slider-track"
+        })
+    },
+
+    _init: function () {
+        BI.IntervalSlider.superclass._init.apply(this, arguments);
+
+        var self = this;
+        var c = this._constant;
+        this.enable = false;
+        this.valueOne = "";
+        this.valueTwo = "";
+        this.calculation = new BI.AccurateCalculationModel();
+
+        this.backgroundTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "background-track",
+            height: c.TRACK_HEIGHT
+        });
+        this.grayTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "gray-track",
+            height: 8
+        });
+        this.blueTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "blue-track",
+            height: 8
+        });
+        this.track = this._createTrackWrapper();
+
+        this.labelOne = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            allowBlank: false,
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.labelOne.on(BI.Editor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));//分成1000份
+            self._setLabelOnePosition(significantPercent);
+            self._setSliderOnePosition(significantPercent);
+            self._setBlueTrack();
+            self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+        });
+
+        this.labelTwo = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            allowBlank: false,
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.labelTwo.on(BI.Editor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));
+            self._setLabelTwoPosition(significantPercent);
+            self._setSliderTwoPosition(significantPercent);
+            self._setBlueTrack();
+            self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+        });
+
+        this.sliderOne = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.sliderOne.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setLabelOnePosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.labelOne.setValue(v);
+                self.valueOne = v;
+                self._setBlueTrack();
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderOnePosition(significantPercent);
+                self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+            }
+        });
+
+        this.sliderTwo = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.sliderTwo.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setLabelTwoPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.labelTwo.setValue(v);
+                self.valueTwo = v;
+                self._setBlueTrack();
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderTwoPosition(significantPercent);
+                self.fireEvent(BI.IntervalSlider.EVENT_CHANGE);
+            }
+        });
+        this._setVisible(false);
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.track,
+                            width: "100%",
+                            height: c.TRACK_HEIGHT
+                        }]
+                    }],
+                    hgap: 7,
+                    height: c.TRACK_HEIGHT
+                },
+                top: 33,
+                left: 0,
+                width: "100%"
+            },
+                this._createLabelWrapper(),
+                this._createSliderWrapper()
+            ]
+        })
+    },
+
+    _createLabelWrapper: function () {
+        var c = this._constant;
+        return {
+            el: {
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.labelOne,
+                        top: 0,
+                        left: "0%"
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.labelTwo,
+                        top: 0,
+                        left: "100%"
+                    }]
+                }],
+                rgap: c.EDITOR_WIDTH,
+                height: 90
+            },
+            top: 0,
+            left: 0,
+            width: "100%"
+        }
+    },
+
+    _createSliderWrapper: function () {
+        var c = this._constant;
+        return {
+            el: {
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.sliderOne,
+                        top: 0,
+                        left: "0%"
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.sliderTwo,
+                        top: 0,
+                        left: "100%"
+                    }]
+                }],
+                hgap: c.SLIDER_WIDTH_HALF,
+                height: c.SLIDER_HEIGHT
+            },
+            top: 30,
+            left: 0,
+            width: "100%"
+        }
+    },
+
+    _createTrackWrapper: function () {
+        return BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.backgroundTrack,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.grayTrack,
+                            top: 0,
+                            left: 0,
+                            width: "100%"
+                        }, {
+                            el: this.blueTrack,
+                            top: 0,
+                            left: 0,
+                            width: "0%"
+                        }]
+                    }],
+                    hgap: 8,
+                    height: 8
+                },
+                top: 8,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _checkValidation: function (v) {
+        return !(BI.isNull(v) || v < this.min || v > this.max)
+    },
+
+    _checkOverlap: function () {
+        var labelOneLeft = this.labelOne.element[0].offsetLeft;
+        var labelTwoLeft = this.labelTwo.element[0].offsetLeft;
+        if (labelOneLeft <= labelTwoLeft) {
+            if ((labelTwoLeft - labelOneLeft) < 90) {
+                this.labelTwo.element.css({"top": 60});
+            } else {
+                this.labelTwo.element.css({"top": 0});
+            }
+        } else {
+            if ((labelOneLeft - labelTwoLeft) < 90) {
+                this.labelTwo.element.css({"top": 60});
+            } else {
+                this.labelTwo.element.css({"top": 0});
+            }
+        }
+    },
+
+    _setLabelOnePosition: function (percent) {
+        this.labelOne.element.css({"left": percent + "%"});
+        this._checkOverlap();
+    },
+
+    _setLabelTwoPosition: function (percent) {
+        this.labelTwo.element.css({"left": percent + "%"});
+        this._checkOverlap();
+    },
+
+    _setSliderOnePosition: function (percent) {
+        this.sliderOne.element.css({"left": percent + "%"});
+    },
+
+    _setSliderTwoPosition: function (percent) {
+        this.sliderTwo.element.css({"left": percent + "%"});
+    },
+
+    _setBlueTrackLeft: function (percent) {
+        this.blueTrack.element.css({"left": percent + "%"});
+    },
+
+    _setBlueTrackWidth: function (percent) {
+        this.blueTrack.element.css({"width": percent + "%"});
+    },
+
+    _setBlueTrack: function () {
+        var percentOne = this._getPercentByValue(this.labelOne.getValue());
+        var percentTwo = this._getPercentByValue(this.labelTwo.getValue());
+        if (percentOne <= percentTwo) {
+            this._setBlueTrackLeft(percentOne);
+            this._setBlueTrackWidth(percentTwo - percentOne);
+        } else {
+            this._setBlueTrackLeft(percentTwo);
+            this._setBlueTrackWidth(percentOne - percentTwo);
+        }
+    },
+
+    _setAllPosition: function (one, two) {
+        this._setSliderOnePosition(one);
+        this._setLabelOnePosition(one);
+        this._setSliderTwoPosition(two);
+        this._setLabelTwoPosition(two);
+        this._setBlueTrack();
+    },
+
+    _setVisible: function (visible) {
+        this.sliderOne.setVisible(visible);
+        this.sliderTwo.setVisible(visible);
+        this.labelOne.setVisible(visible);
+        this.labelTwo.setVisible(visible);
+    },
+
+    _setErrorText: function () {
+        var errorText = BI.i18nText("BI-Please_Enter") + this.min + "-" + this.max + BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Basic_Number");
+        this.labelOne.setErrorText(errorText);
+        this.labelTwo.setErrorText(errorText);
+    },
+
+    _getGrayTrackLength: function () {
+        return this.grayTrack.element[0].scrollWidth
+    },
+
+    _getValueByPercent: function (percent) {//return (((max-min)*percent)/100+min)
+        var sub = this.calculation.accurateSubtraction(this.max, this.min);
+        var mul = this.calculation.accurateMultiplication(sub, percent);
+        var div = this.calculation.accurateDivisionTenExponent(mul, 2);
+        return this.calculation.accurateAddition(div, this.min);
+    },
+
+    _getPercentByValue: function (v) {
+        return (v - this.min) * 100 / (this.max - this.min);
+    },
+
+    _setDraggableEnable: function (enable) {
+        if (enable) {
+            this.sliderOne.element.draggable("enable");
+            this.sliderTwo.element.draggable("enable")
+        } else {
+            this.sliderOne.element.draggable("disable");
+            this.sliderTwo.element.draggable("disable")
+        }
+    },
+
+    getValue: function () {
+        if (this.valueOne <= this.valueTwo) {
+            return {min: this.valueOne, max: this.valueTwo}
+        } else {
+            return {min: this.valueTwo, max: this.valueOne}
+        }
+    },
+
+    setMinAndMax: function (v) {
+        var minNumber = BI.parseFloat(v.min);
+        var maxNumber = BI.parseFloat(v.max);
+        if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber >= minNumber )) {
+            this.min = minNumber;
+            this.max = maxNumber;
+            this.valueOne = minNumber;
+            this.valueTwo = maxNumber;
+            this._setDraggableEnable(true);
+        }
+        if (maxNumber === minNumber) {
+            this._setDraggableEnable(false);
+        }
+    },
+
+    setValue: function (v) {
+        var valueOne = BI.parseFloat(v.min);
+        var valueTwo = BI.parseFloat(v.max);
+        if (!isNaN(valueOne) && !isNaN(valueTwo)) {
+            if (this._checkValidation(valueOne)) {
+                this.valueOne = valueOne;
+            }
+            if (this._checkValidation(valueTwo)) {
+                this.valueTwo = valueTwo;
+            }
+            if (valueOne < this.min) {
+                this.valueOne = this.min;
+            }
+            if (valueTwo > this.max) {
+                this.valueTwo = this.max;
+            }
+        }
+    },
+
+    reset: function () {
+        this._setVisible(false);
+        this.enable = false;
+        this.valueOne = "";
+        this.valueTwo = "";
+        this.min = NaN;
+        this.max = NaN;
+        this._setBlueTrackWidth(0);
+    },
+
+    populate: function () {
+        if (!isNaN(this.min) && !isNaN(this.max)) {
+            this.enable = true;
+            this._setVisible(true);
+            this._setErrorText();
+            if ((BI.isNumeric(this.valueOne) || BI.isNotEmptyString(this.valueOne)) && (BI.isNumeric(this.valueTwo) || BI.isNotEmptyString(this.valueTwo))) {
+                this.labelOne.setValue(this.valueOne);
+                this.labelTwo.setValue(this.valueTwo);
+                this._setAllPosition(this._getPercentByValue(this.valueOne), this._getPercentByValue(this.valueTwo));
+            } else {
+                this.labelOne.setValue(this.min);
+                this.labelTwo.setValue(this.max);
+                this._setAllPosition(0, 100)
+            }
+        }
+    }
+});
+BI.IntervalSlider.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.interval_slider", BI.IntervalSlider);
\ No newline at end of file
diff --git a/src/widget/intervalslider/model.accuratecalculation.js b/src/widget/intervalslider/model.accuratecalculation.js
new file mode 100644
index 000000000..310b39d02
--- /dev/null
+++ b/src/widget/intervalslider/model.accuratecalculation.js
@@ -0,0 +1,222 @@
+/**
+ * Created by zcf on 2017/3/1.
+ * 万恶的IEEE-754
+ * 使用字符串精确计算含小数加法、减法、乘法和10的指数倍除法,支持负数
+ */
+BI.AccurateCalculationModel = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.AccurateCalculationModel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: ""
+        })
+    },
+
+    _init: function () {
+        BI.AccurateCalculationModel.superclass._init.apply(this, arguments);
+    },
+
+    _getMagnitude: function (n) {
+        var magnitude = "1";
+        for (var i = 0; i < n; i++) {
+            magnitude += "0";
+        }
+        return BI.parseInt(magnitude);
+    },
+
+    _formatDecimal: function (stringNumber1, stringNumber2) {
+        if (stringNumber1.numDecimalLength === stringNumber2.numDecimalLength) {
+            return;
+        }
+        var magnitudeDiff = stringNumber1.numDecimalLength - stringNumber2.numDecimalLength;
+        if (magnitudeDiff > 0) {
+            var needAddZero = stringNumber2
+        } else {
+            var needAddZero = stringNumber1;
+            magnitudeDiff = (0 - magnitudeDiff);
+        }
+        for (var i = 0; i < magnitudeDiff; i++) {
+            if (needAddZero.numDecimal === "0" && i === 0) {
+                continue
+            }
+            needAddZero.numDecimal += "0"
+        }
+    },
+
+    _stringNumberFactory: function (num) {
+        var strNum = num.toString();
+        var numStrArray = strNum.split(".");
+        var numInteger = numStrArray[0];
+        if (numStrArray.length === 1) {
+            var numDecimal = "0";
+            var numDecimalLength = 0;
+        } else {
+            var numDecimal = numStrArray[1];
+            var numDecimalLength = numStrArray[1].length;
+        }
+        return {
+            "numInteger": numInteger,
+            "numDecimal": numDecimal,
+            "numDecimalLength": numDecimalLength
+        }
+    },
+
+    _accurateSubtraction: function (num1, num2) {//num1-num2 && num1>num2
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) - BI.parseInt(stringNumber2.numInteger);
+        //小数部分
+        this._formatDecimal(stringNumber1, stringNumber2);
+        var decimalMaxLength = getDecimalMaxLength(stringNumber1, stringNumber2);
+
+        if (BI.parseInt(stringNumber1.numDecimal) >= BI.parseInt(stringNumber2.numDecimal)) {
+            var decimalResultTemp = (BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
+            var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
+        } else {//否则借位
+            integerResult--;
+            var borrow = this._getMagnitude(decimalMaxLength);
+            var decimalResultTemp = (borrow + BI.parseInt(stringNumber1.numDecimal) - BI.parseInt(stringNumber2.numDecimal)).toString();
+            var decimalResult = addZero(decimalResultTemp, decimalMaxLength);
+        }
+        var result = integerResult + "." + decimalResult;
+        return BI.parseFloat(result);
+
+        function getDecimalMaxLength(num1, num2) {
+            if (num1.numDecimal.length >= num2.numDecimal.length) {
+                return num1.numDecimal.length
+            }
+            return num2.numDecimal.length
+        }
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    _accurateAddition: function (num1, num2) {//加法结合律
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) + BI.parseInt(stringNumber2.numInteger);
+        //小数部分
+        this._formatDecimal(stringNumber1, stringNumber2);
+
+        var decimalResult = (BI.parseInt(stringNumber1.numDecimal) + BI.parseInt(stringNumber2.numDecimal)).toString();
+
+        if (decimalResult !== "0") {
+            if (decimalResult.length <= stringNumber1.numDecimal.length) {
+                decimalResult = addZero(decimalResult, stringNumber1.numDecimal.length)
+            } else {
+                integerResult++;//进一
+                decimalResult = decimalResult.slice(1);
+            }
+        }
+        var result = integerResult + "." + decimalResult;
+        return BI.parseFloat(result);
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    _accurateMultiplication: function (num1, num2) {//乘法分配律
+        var stringNumber1 = this._stringNumberFactory(num1);
+        var stringNumber2 = this._stringNumberFactory(num2);
+        //整数部分计算
+        var integerResult = BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numInteger);
+        //num1的小数和num2的整数
+        var dec1Int2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numInteger), stringNumber1.numDecimalLength);
+        //num1的整数和num2的小数
+        var int1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numInteger) * BI.parseInt(stringNumber2.numDecimal), stringNumber2.numDecimalLength);
+        //小数*小数
+        var dec1dec2 = this._accurateDivisionTenExponent(BI.parseInt(stringNumber1.numDecimal) * BI.parseInt(stringNumber2.numDecimal), (stringNumber1.numDecimalLength + stringNumber2.numDecimalLength));
+
+        return this._accurateAddition(this._accurateAddition(this._accurateAddition(integerResult, dec1Int2), int1dec2), dec1dec2);
+    },
+
+    _accurateDivisionTenExponent: function (num, n) {// num/10^n && n>0
+        var stringNumber = this._stringNumberFactory(num);
+        if (stringNumber.numInteger.length > n) {
+            var integerResult = stringNumber.numInteger.slice(0, (stringNumber.numInteger.length - n));
+            var partDecimalResult = stringNumber.numInteger.slice(-n);
+        } else {
+            var integerResult = "0";
+            var partDecimalResult = addZero(stringNumber.numInteger, n);
+        }
+        var result = integerResult + "." + partDecimalResult + stringNumber.numDecimal;
+        return BI.parseFloat(result);
+
+        function addZero(resultTemp, length) {
+            var diff = length - resultTemp.length;
+            for (var i = 0; i < diff; i++) {
+                resultTemp = "0" + resultTemp;
+            }
+            return resultTemp
+        }
+    },
+
+    accurateSubtraction: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            if (num1 >= num2) {
+                return this._accurateSubtraction(num1, num2)
+            }
+            return this._accurateSubtraction(num2, num1)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return this._accurateAddition(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return -this._accurateAddition(-num1, num2)
+        }
+        if (num1 < 0 && num2 < 0) {
+            if (num1 >= num2) {
+                return this._accurateSubtraction(-num2, -num1)
+            }
+            return this._accurateSubtraction(-num1, -num2)
+        }
+    },
+
+    accurateAddition: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            return this._accurateAddition(num1, num2)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return this.accurateSubtraction(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return this.accurateSubtraction(num2, -num1)
+        }
+        if (num1 < 0 && num2 < 0) {
+            return -this._accurateAddition(-num1, -num2)
+        }
+    },
+
+    accurateMultiplication: function (num1, num2) {
+        if (num1 >= 0 && num2 >= 0) {
+            return this._accurateMultiplication(num1, num2)
+        }
+        if (num1 >= 0 && num2 < 0) {
+            return -this._accurateMultiplication(num1, -num2)
+        }
+        if (num1 < 0 && num2 >= 0) {
+            return -this._accurateMultiplication(-num1, num2)
+        }
+        if (num1 < 0 && num2 < 0) {
+            return this._accurateMultiplication(-num1, -num2)
+        }
+    },
+
+    accurateDivisionTenExponent: function (num1, n) {
+        if (num1 >= 0) {
+            return this._accurateDivisionTenExponent(num1, n);
+        }
+        return -this._accurateDivisionTenExponent(-num1, n);
+    }
+});
\ No newline at end of file
diff --git a/src/widget/listlabel/group.item.listlabel.js b/src/widget/listlabel/group.item.listlabel.js
new file mode 100644
index 000000000..c03011d81
--- /dev/null
+++ b/src/widget/listlabel/group.item.listlabel.js
@@ -0,0 +1,136 @@
+/**
+ * Created by fay on 2016/9/14.
+ */
+BI.ListLabelItemGroup = BI.inherit(BI.ButtonGroup, {
+    _defaultConfig: function () {
+        return BI.extend(BI.ListLabelItemGroup.superclass._defaultConfig.apply(this, arguments), {
+            chooseType: BI.Selection.Multi
+        });
+    },
+
+    _init: function () {
+        BI.ListLabelItemGroup.superclass._init.apply(this, arguments);
+        this.otherValues = [];
+        if (BI.isEmptyArray(this.getValue())) {
+            BI.each(this.buttons, function (idx, button) {
+                if (button.getValue() === BICst.LIST_LABEL_TYPE.ALL) {
+                    button.setSelected(true);
+                }
+            });
+        }
+        this._checkBtnStyle();
+    },
+
+    _createBtns: function (items) {
+        var o = this.options;
+        return BI.createWidgets(BI.createItems(items, {
+            type: "bi.text_button",
+            cls: "list-label-button"
+        }));
+    },
+
+
+    _btnsCreator: function (items) {
+        var self = this, args = Array.prototype.slice.call(arguments), o = this.options;
+        var buttons = this._createBtns(items);
+        args[0] = buttons;
+
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    switch (o.chooseType) {
+                        case BI.ButtonGroup.CHOOSE_TYPE_MULTI:
+                            if (btn.getValue() === BICst.LIST_LABEL_TYPE.ALL) {
+                                self.setValue([BICst.LIST_LABEL_TYPE.ALL]);
+                            } else {
+                                self._checkBtnState();
+                            }
+                            self._checkBtnStyle();
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                            self.setValue(btn.getValue());
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_NONE:
+                            self.setValue([]);
+                            break;
+                    }
+                    self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            btn.on(BI.Events.DESTROY, function () {
+                BI.remove(self.buttons, btn);
+            });
+        });
+
+        return buttons;
+    },
+
+    _checkBtnState: function () {
+        if (BI.isEmptyArray(this.getValue()) && BI.isEmptyArray(this.otherValues)) {
+            this.buttons[0].setSelected(true);
+            this.fireEvent(BI.ButtonGroup.EVENT_CHANGE, this.buttons[0].getValue(), this.buttons[0]);
+        } else if (this.getValue().length === 1 && BI.isEqual(this.getValue()[0], BICst.LIST_LABEL_TYPE.ALL)) {
+            this.buttons[0].setSelected(true);
+        }
+        else {
+            this.buttons[0].setSelected(false);
+        }
+    },
+
+    _checkBtnStyle: function () {
+        BI.each(this.buttons, function (idx, btn) {
+            if (btn.isSelected()) {
+                btn.doHighLight();
+            } else {
+                btn.unHighLight();
+            }
+        });
+    },
+
+    removeAllItems: function () {
+        var indexes = [];
+        for (var i = 1; i < this.buttons.length; i++) {
+            indexes.push(i);
+        }
+        this.removeItemAt(indexes);
+    },
+
+    setValue: function (v) {
+        var self = this;
+        v = BI.isArray(v) ? v : [v];
+        BI.each(this.buttons, function (i, item) {
+            if (BI.deepContains(v, item.getValue())) {
+                item.setSelected && item.setSelected(true);
+            } else {
+                item.setSelected && item.setSelected(false);
+            }
+        });
+        var currentValues = this.getValue();
+        this.otherValues = [];
+        BI.each(v, function (idx, value) {
+            if (currentValues.indexOf(value) === -1) {
+                self.otherValues.push(value);
+            }
+        });
+        this._checkBtnState();
+        this._checkBtnStyle();
+
+    },
+
+    getValue: function () {
+        var v = [];
+        BI.each(this.buttons, function (i, item) {
+            if (item.isEnabled() && item.isSelected && item.isSelected()) {
+                v.push(item.getValue());
+            }
+        });
+        v = v.concat(this.otherValues || []);
+        return v;
+    }
+});
+
+$.shortcut('bi.list_label_item_group', BI.ListLabelItemGroup);
diff --git a/src/widget/listlabel/listlabel.js b/src/widget/listlabel/listlabel.js
new file mode 100644
index 000000000..dacb22ffa
--- /dev/null
+++ b/src/widget/listlabel/listlabel.js
@@ -0,0 +1,160 @@
+/**
+ * 文本标签
+ *
+ * Created by fay on 2016/9/11.
+ */
+BI.ListLabel = BI.inherit(BI.Widget, {
+
+    _constant: {
+        MAX_COLUMN_SIZE: 40,
+        DEFAULT_LABEL_GAP: 15,
+        DEFAULT_RIGHT_GAP: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ListLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-list-label",
+            title: BI.i18nText("BI-List_Label_Con"),
+            showTitle: true,
+            items: [],
+            height: 40
+        })
+    },
+
+    _init: function () {
+        BI.ListLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.items = BI.clone(o.items);
+        this.items.unshift({
+            text: BI.i18nText("BI-Basic_Nolimited"),
+            value: BICst.LIST_LABEL_TYPE.ALL
+        });
+        this.title = BI.createWidget({
+            type: "bi.label",
+            text: o.title + BI.i18nText("BI-Basic_Colon"),
+            title: o.title,
+            height: o.height
+        });
+
+        this.container = BI.createWidget({
+            type: "bi.list_label_item_group",
+            items: BI.createItems(this.items.slice(0, this._constant.MAX_COLUMN_SIZE), {
+                type: "bi.text_button",
+                height: o.height,
+                rgap: this._constant.DEFAULT_RIGHT_GAP
+            }),
+            layouts: [{
+                type: "bi.inline_vertical_adapt",
+                rgap: this._constant.DEFAULT_LABEL_GAP,
+                height: o.height
+            }]
+        });
+        this.container.on(BI.ButtonGroup.EVENT_CHANGE, function (value) {
+            self.fireEvent(BI.ListLabel.EVENT_CHANGE, value);
+        });
+        this.minTip = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-No_Selected_Value"),
+            disabled: true,
+            height: o.height
+        });
+        this.maxTip = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-Max_Show_40_Labels"),
+            disabled: true,
+            height: o.height
+        });
+
+        this.checkTipsState(o.items);
+        this.right = BI.createWidget({
+            type: "bi.horizontal",
+            items: [this.container, this.minTip, this.maxTip],
+            height: o.height
+        });
+
+        o.showTitle ? BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.title,
+                left:0,
+                right:0,
+                top:0,
+                bottom:0,
+                width: 60
+            }, {
+                el: this.right,
+                left: 65,
+                right:0,
+                top:0,
+                bottom:0
+            }],
+            element: this
+        }) : BI.createWidget({
+            type: "bi.horizontal",
+            items: [this.right],
+            element: this
+        });
+    },
+
+    addItems: function (v) {
+        this.checkTipsState(v);
+        this.container.addItems(v.slice(0, this._constant.MAX_COLUMN_SIZE - 1));
+    },
+
+    checkTipsState: function (v) {
+        if (BI.isEmptyArray(v)) {
+            this.minTip.setVisible(true);
+            this.container.setVisible(false);
+        } else {
+            this.minTip.setVisible(false);
+            this.container.setVisible(true);
+        }
+        if (v.length >= this._constant.MAX_COLUMN_SIZE) {
+            this.maxTip.setVisible(true);
+        } else {
+            this.maxTip.setVisible(false);
+        }
+    },
+
+    removeAllItems: function () {
+        this.container.removeAllItems();
+    },
+
+    getSelectedButtons: function () {
+        return this.container.isVisible() ? this.container.getSelectedButtons() : [];
+    },
+
+    getAllButtons: function () {
+        return this.container.getAllButtons();
+    },
+
+    setTitle: function (title) {
+        this.title.setText(title + BI.i18nText("BI-Basic_Colon"));
+        this.title.setTitle(title);
+    },
+
+    setItems: function (items) {
+        this.removeAllItems();
+        this.addItems(BI.createItems(items, {
+            type: "bi.text_button",
+            height: this.options.height,
+            rgap: this._constant.DEFAULT_RIGHT_GAP
+        }));
+    },
+
+    populate: function (v) {
+        this.setTitle(v.title || BI.i18nText("BI-List_Label_Con"));
+        this.setItems(v.items || []);
+    },
+
+    setValue: function (v) {
+        this.container.setValue(v);
+    },
+
+    getValue: function () {
+        return this.container.getValue();
+    }
+});
+
+BI.ListLabel.EVENT_CHANGE = 'BI.ListLabel.EVENT_CHANGE';
+$.shortcut('bi.list_label', BI.ListLabel);
\ No newline at end of file
diff --git a/src/widget/month/combo.month.js b/src/widget/month/combo.month.js
new file mode 100644
index 000000000..38bf707f3
--- /dev/null
+++ b/src/widget/month/combo.month.js
@@ -0,0 +1,79 @@
+/**
+ * 月份下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.MonthCombo
+ * @extends BI.Trigger
+ */
+BI.MonthCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.MonthCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.month_trigger"
+        });
+
+        this.trigger.on(BI.MonthTrigger.EVENT_CONFIRM, function (v) {
+            if(this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getValue());
+            }else if(!this.getKey()){
+                self.setValue();
+            }
+            self.fireEvent(BI.MonthCombo.EVENT_CONFIRM);
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_START, function () {
+            self.combo.hideView();
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_STOP, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+        this.trigger.on(BI.MonthTrigger.EVENT_CHANGE, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.month_popup"
+        });
+        this.popup.on(BI.MonthPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MonthCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                el: this.popup
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+
+BI.MonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.month_combo', BI.MonthCombo);
\ No newline at end of file
diff --git a/src/widget/month/popup.month.js b/src/widget/month/popup.month.js
new file mode 100644
index 000000000..9a1715bdc
--- /dev/null
+++ b/src/widget/month/popup.month.js
@@ -0,0 +1,81 @@
+/**
+ * 月份展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.MonthPopup
+ * @extends BI.Trigger
+ */
+BI.MonthPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-month-popup"
+        });
+    },
+
+    _init: function () {
+        BI.MonthPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        //纵向排列月
+        var month = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11];
+        var items = [];
+        items.push(month.slice(0, 2));
+        items.push(month.slice(2, 4));
+        items.push(month.slice(4, 6));
+        items.push(month.slice(6, 8));
+        items.push(month.slice(8, 10));
+        items.push(month.slice(10, 12));
+        items = BI.map(items, function (i, item) {
+            return BI.map(item, function (j, td) {
+                return {
+                    type: "bi.text_item",
+                    cls: "bi-list-item-active",
+                    textAlign: "center",
+                    whiteSpace: "nowrap",
+                    once: false,
+                    forceSelected: true,
+                    height: 23,
+                    width: 38,
+                    value: td,
+                    text: td + 1
+                };
+            });
+        });
+
+        this.month = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(items, {}),
+            layouts: [BI.LogicFactory.createLogic("table", BI.extend({
+                dynamic: true
+            }, {
+                columns: 2,
+                rows: 6,
+                columnSize: [1 / 2, 1 / 2],
+                rowSize: 25
+            })), {
+                type: "bi.center_adapt",
+                vgap: 1,
+                hgap: 2
+            }]
+        });
+
+        this.month.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MonthPopup.EVENT_CHANGE);
+            }
+        })
+    },
+
+    getValue: function () {
+        return this.month.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.month.setValue([v]);
+    }
+});
+BI.MonthPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.month_popup", BI.MonthPopup);
\ No newline at end of file
diff --git a/src/widget/month/trigger.month.js b/src/widget/month/trigger.month.js
new file mode 100644
index 000000000..c835f7e2e
--- /dev/null
+++ b/src/widget/month/trigger.month.js
@@ -0,0 +1,111 @@
+/**
+ * 月份trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.MonthTrigger
+ * @extends BI.Trigger
+ */
+BI.MonthTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 25,
+        errorText: BI.i18nText("BI-Month_Trigger_Error_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MonthTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-month-trigger",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.MonthTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 12);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.MonthTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.MonthTrigger.EVENT_STOP);
+        });
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        text: BI.i18nText("BI-Multi_Date_Month"),
+                        baseCls: "bi-trigger-month-text",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+    setValue: function (v) {
+        if(BI.isNotNull(v)){
+            this.editor.setState(v + 1);
+            this.editor.setValue(v + 1);
+            this.editor.setTitle(v + 1);
+            return;
+        }
+        this.editor.setState();
+        this.editor.setValue();
+        this.editor.setTitle();
+    },
+    getKey: function () {
+        return this.editor.getValue() | 0;
+    },
+    getValue: function () {
+        return this.editor.getValue() - 1;
+    }
+});
+BI.MonthTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.MonthTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.MonthTrigger.EVENT_START = "EVENT_START";
+BI.MonthTrigger.EVENT_STOP = "EVENT_STOP";
+BI.MonthTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.month_trigger", BI.MonthTrigger);
\ No newline at end of file
diff --git a/src/widget/move2group/button.add.move2group.js b/src/widget/move2group/button.add.move2group.js
new file mode 100644
index 000000000..a47295cc5
--- /dev/null
+++ b/src/widget/move2group/button.add.move2group.js
@@ -0,0 +1,59 @@
+/**
+ * 新建并选中某个分组按钮
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupAddButton
+ * @extends BI.BasicButton
+ */
+BI.Move2GroupAddButton = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        var conf = BI.Move2GroupAddButton.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + ' bi-move2group-add-button',
+            shadow: true,
+            isShadowShowingOnSelected: true,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.Move2GroupAddButton.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            text: BI.i18nText("BI-Create_And_Move_To") + "\"江苏\"",
+            height: o.height
+        })
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.icon_button",
+                    cls: "move2group-add-font"
+                },
+                width: 30
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    setValue: function (v) {
+        this.text.setValue(BI.i18nText("BI-Create_And_Move_To") + "\"" + v + "\"");
+        this.setTitle(BI.i18nText("BI-Create_And_Move_To") + "\"" + v + "\"", {
+            container: "body"
+        });
+    },
+
+    doClick: function () {
+        BI.Move2GroupAddButton.superclass.doClick.apply(this, arguments);
+        if (this.isValid()) {
+            this.fireEvent(BI.Move2GroupAddButton.EVENT_CHANGE);
+        }
+    }
+});
+BI.Move2GroupAddButton.EVENT_CHANGE = "Move2GroupAddButton.EVENT_CHANGE";
+$.shortcut('bi.move2group_add_button', BI.Move2GroupAddButton);
\ No newline at end of file
diff --git a/src/widget/move2group/combo.move2group.js b/src/widget/move2group/combo.move2group.js
new file mode 100644
index 000000000..e36593b4c
--- /dev/null
+++ b/src/widget/move2group/combo.move2group.js
@@ -0,0 +1,136 @@
+/**
+ * 移动到分组下拉框
+ *
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupCombo
+ * @extends BI.Widget
+ */
+BI.Move2GroupCombo = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        var conf = BI.Move2GroupCombo.superclass._defaultConfig.apply(this, arguments)
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-move2group-combo",
+            height: 30,
+            tipType: "warning",
+            items: []
+        });
+    },
+    _init: function () {
+        BI.Move2GroupCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.button",
+            text: BI.i18nText("BI-Move_To_Group"),
+            title: o.title,
+            height: o.height
+        });
+
+        this.tools = BI.createWidget({
+            type: "bi.move2group_bar"
+        });
+
+        this.tools.on(BI.Move2GroupBar.EVENT_START, function () {
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_EMPTY, function () {
+            self.combo.adjustHeight();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_CLICK_BUTTON, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CLICK_NEW_BUTTON);
+            self.searcher.stopSearch();
+            self.combo.hideView();
+        });
+        this.tools.on(BI.Move2GroupBar.EVENT_CHANGE, function () {
+            this.setButtonVisible(!self.searcher.hasMatched());
+            self.combo.adjustHeight();
+            self.searcher.adjustHeight();
+        });
+
+        this.popup = this._createPopup(this.options.items);
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: this.tools,
+            adapter: this.popup
+        });
+
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CONFIRM);
+            self.combo.hideView();
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            el: this.trigger,
+            isNeedAdjustWidth: false,
+            popup: {
+                width: 200,
+                stopPropagation: false,
+                el: this.popup,
+                tool: this.searcher
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_CHANGE, function () {
+            self.combo.hideView();
+            self.fireEvent(BI.Move2GroupCombo.EVENT_CONFIRM);
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.Move2GroupCombo.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.searcher.stopSearch();
+        })
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.single_select_item",
+            height: 25,
+            handler: function (v) {
+
+            }
+        })
+    },
+
+    _createPopup: function (items, opt) {
+        return BI.createWidget(BI.extend({
+            type: "bi.button_group",
+            items: this._createItems(items),
+            chooseType: 0,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        }, opt));
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        this.combo.populate(this._createItems(items));
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+    setEnable: function (enable) {
+        this.combo.setEnable.apply(this.combo, arguments);
+    },
+
+    getTargetValue: function () {
+        return this.tools.getValue();
+    },
+
+    getValue: function () {
+        var value = this.searcher.getValue();
+        return value[0];
+
+    }
+});
+BI.Move2GroupCombo.EVENT_BEFORE_POPUPVIEW = "Move2GroupCombo.EVENT_BEFORE_POPUPVIEW";
+BI.Move2GroupCombo.EVENT_CHANGE = "Move2GroupCombo.EVENT_CHANGE";
+BI.Move2GroupCombo.EVENT_CONFIRM = "Move2GroupCombo.EVENT_CONFIRM";
+BI.Move2GroupCombo.EVENT_CLICK_NEW_BUTTON = "Move2GroupCombo.EVENT_CLICK_NEW_BUTTON";
+$.shortcut('bi.move2group_combo', BI.Move2GroupCombo);
\ No newline at end of file
diff --git a/src/widget/move2group/toolbar.move2group.js b/src/widget/move2group/toolbar.move2group.js
new file mode 100644
index 000000000..e3782ba92
--- /dev/null
+++ b/src/widget/move2group/toolbar.move2group.js
@@ -0,0 +1,85 @@
+/**
+ * guy
+ * 复选导航条
+ * Created by GUY on 2015/9/25.
+ * @class BI.Move2GroupBar
+ * @extends BI.Widget
+ */
+BI.Move2GroupBar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Move2GroupBar.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-move2group-bar"
+        })
+    },
+    _init: function () {
+        BI.Move2GroupBar.superclass._init.apply(this, arguments);
+        var self = this;
+        this.search = BI.createWidget({
+            type: "bi.text_editor",
+            watermark: BI.i18nText("BI-Search_And_Create_Group"),
+            allowBlank: true
+        });
+
+        this.search.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+
+        this.search.on(BI.TextEditor.EVENT_CHANGE, function () {
+            self.button.setValue(this.getValue());
+            if (this.getValue() !== "") {
+                self.fireEvent(BI.Move2GroupBar.EVENT_CHANGE);
+            }
+        });
+
+        this.search.on(BI.TextEditor.EVENT_EMPTY, function () {
+            self.button.invisible();
+            self.fireEvent(BI.Move2GroupBar.EVENT_EMPTY);
+        });
+
+        this.search.on(BI.TextEditor.EVENT_START, function () {
+            self.button.visible();
+            self.fireEvent(BI.Move2GroupBar.EVENT_START);
+        });
+
+        this.button = BI.createWidget({
+            type: "bi.move2group_add_button"
+        });
+
+        this.button.on(BI.Move2GroupAddButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Move2GroupBar.EVENT_CLICK_BUTTON);
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            vgap: 5,
+            hgap: 5,
+            items: [this.search, this.button]
+        });
+
+        this.button.invisible();
+    },
+
+    blur: function(){
+        this.search.blur();
+    },
+
+    setButtonVisible: function (b) {
+        this.button.setVisible(b);
+    },
+
+    getValue: function () {
+        return this.search.getValue();
+    },
+
+    setValue: function (v) {
+        this.search.setValue(v);
+        this.button.setValue(v);
+    }
+});
+BI.Move2GroupBar.EVENT_START = "Move2GroupBar.EVENT_START";
+BI.Move2GroupBar.EVENT_EMPTY = "Move2GroupBar.EVENT_EMPTY";
+BI.Move2GroupBar.EVENT_CHANGE = "Move2GroupBar.EVENT_CHANGE";
+BI.Move2GroupBar.EVENT_CLICK_BUTTON = "Move2GroupBar.EVENT_CLICK_BUTTON";
+$.shortcut("bi.move2group_bar", BI.Move2GroupBar);
\ No newline at end of file
diff --git a/src/widget/muiltitextlabel/group.item.text.label.js b/src/widget/muiltitextlabel/group.item.text.label.js
new file mode 100644
index 000000000..a9b9b92e5
--- /dev/null
+++ b/src/widget/muiltitextlabel/group.item.text.label.js
@@ -0,0 +1,80 @@
+/**
+ * Created by fay on 2016/9/14.
+ */
+BI.TextLabelItemGroup = BI.inherit(BI.ButtonGroup, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextLabelItemGroup.superclass._defaultConfig.apply(this, arguments), {
+            chooseType: BI.Selection.Multi
+        });
+    },
+
+    _init: function () {
+        BI.TextLabelItemGroup.superclass._init.apply(this, arguments);
+        this._checkBtnStyle();
+    },
+
+    _btnsCreator: function (items) {
+        var self = this, args = Array.prototype.slice.call(arguments), o = this.options;
+        var buttons = this._createBtns(items);
+        args[0] = buttons;
+
+        BI.each(this.behaviors, function (i, behavior) {
+            behavior.doBehavior.apply(behavior, args);
+        });
+        BI.each(buttons, function (i, btn) {
+            btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) {
+                if (type === BI.Events.CLICK) {
+                    switch (o.chooseType) {
+                        case BI.ButtonGroup.CHOOSE_TYPE_MULTI:
+                            if (BI.isEmptyString(btn.getValue())) {
+                                self.setValue([]);
+                            } else {
+                                self._checkBtnStyle();
+                            }
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_SINGLE:
+                            self.setValue(btn.getValue());
+                            break;
+                        case BI.ButtonGroup.CHOOSE_TYPE_NONE:
+                            self.setValue([]);
+                            break;
+                    }
+                    self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj);
+                }
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            btn.on(BI.Events.DESTROY, function () {
+                BI.remove(self.buttons, btn);
+            })
+        });
+
+        return buttons;
+    },
+
+    _checkBtnStyle: function () {
+        var self = this;
+        var flag = BI.isEmptyArray(this.getValue());
+        BI.each(this.buttons, function (idx, btn) {
+            if (flag && BI.isEmptyString(btn.getValue())) {
+                btn.setSelected(true);
+                btn.doHighLight();
+            }
+            if (!flag && BI.isEmptyString(btn.getValue())) {
+                btn.setSelected(false);
+                btn.unHighLight();
+            }
+            if (btn.isSelected()) {
+                btn.doHighLight();
+            } else {
+                btn.unHighLight();
+            }
+        });
+    },
+
+    setValue: function (v) {
+        BI.TextLabelItemGroup.superclass.setValue.apply(this, arguments);
+        this._checkBtnStyle();
+    }
+});
+
+$.shortcut('bi.text_label_item_group', BI.TextLabelItemGroup);
diff --git a/src/widget/muiltitextlabel/text.label.js b/src/widget/muiltitextlabel/text.label.js
new file mode 100644
index 000000000..aec51476c
--- /dev/null
+++ b/src/widget/muiltitextlabel/text.label.js
@@ -0,0 +1,53 @@
+/**
+ * 文本标签
+ *
+ * Created by fay on 2016/9/11.
+ */
+BI.TextLabel = BI.inherit(BI.Widget, {
+
+    _constant: {
+        MAX_COLUMN_SIZE: 40
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.TextLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-label",
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.TextLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var title = BI.createWidget({
+            type: "bi.label",
+            text: o.title + ":"
+        });
+        this.container = BI.createWidget({
+            type: "bi.text_label_item_group",
+            items: BI.createItems(o.items.slice(0, this._constant.MAX_COLUMN_SIZE), {
+                type: "bi.text_button"
+            }),
+            layouts: [{
+                type: "bi.horizontal",
+
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.horizontal",
+            items: [title, this.container],
+            element: this
+        })
+    },
+    
+    setValue: function (v) {
+        this.container.setValue(v);
+    },
+    
+    getValue: function () {
+        return this.container.getValue();
+    }
+});
+
+$.shortcut('bi.text_label', BI.TextLabel);
\ No newline at end of file
diff --git a/src/widget/multidate/abstract.multidate.datepane.js b/src/widget/multidate/abstract.multidate.datepane.js
new file mode 100644
index 000000000..e8787ade4
--- /dev/null
+++ b/src/widget/multidate/abstract.multidate.datepane.js
@@ -0,0 +1,160 @@
+(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.MultiDateCard
+     * @extends BI.Widget
+     * @abstract
+     */
+    BI.MultiDateCard = BI.inherit(BI.Widget, {
+
+        constants: {
+            lgap: 80,
+            itemHeight: 35,
+            defaultEditorValue: "1"
+        },
+
+        _defaultConfig: function () {
+            return $.extend(BI.MultiDateCard.superclass._defaultConfig.apply(this, arguments), {});
+        },
+
+        dateConfig: function () {
+
+        },
+
+        defaultSelectedItem: function () {
+
+        },
+
+        _init: function () {
+            BI.MultiDateCard.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+
+            this.label = BI.createWidget({
+                type: 'bi.label',
+                height: this.constants.itemHeight,
+                textAlign: "left",
+                text: BI.i18nText("BI-Multi_Date_Relative_Current_Time"),
+                cls: 'bi-multidate-inner-label'
+            });
+            this.radioGroup = BI.createWidget({
+                type: "bi.button_group",
+                chooseType: 0,
+                items: BI.createItems(this.dateConfig(), {
+                    type: 'bi.multidate_segment',
+                    height: this.constants.itemHeight
+                }),
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            });
+
+            this.radioGroup.on(BI.Controller.EVENT_CHANGE, function (type) {
+                if (type === BI.Events.CONFIRM) {
+                    self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+                }
+            });
+            this.radioGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+                self.setValue(self.getValue());
+                self.fireEvent(BI.MultiDateCard.EVENT_CHANGE);
+            });
+            BI.createWidget({
+                element: this,
+                type: 'bi.center_adapt',
+                lgap: this.constants.lgap,
+                items: [{
+                    type: 'bi.vertical',
+                    items: [this.label, this.radioGroup]
+                }]
+            });
+        },
+
+        getValue: function () {
+            var button = this.radioGroup.getSelectedButtons()[0];
+            var type = button.getValue(), value = button.getInputValue();
+            return {
+                type: type,
+                value: value
+            }
+        },
+
+        _isTypeAvaliable: function (type) {
+            var res = false;
+            BI.find(this.dateConfig(), function (i, item) {
+                if (item.value === type) {
+                    res = true;
+                    return true;
+                }
+            });
+            return res;
+        },
+
+        setValue: function (v) {
+            var self = this;
+            if (BI.isNotNull(v) && this._isTypeAvaliable(v.type)) {
+                this.radioGroup.setValue(v.type);
+                BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+                    if (button.isEditorExist() === true && button.isSelected()) {
+                        button.setInputValue(v.value);
+                        button.setEnable(true);
+                    } else {
+                        button.setInputValue(self.constants.defaultEditorValue);
+                        button.setEnable(false);
+                    }
+                });
+            } else {
+                this.radioGroup.setValue(this.defaultSelectedItem());
+                BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+                    button.setInputValue(self.constants.defaultEditorValue);
+                    if (button.isEditorExist() === true && button.isSelected()) {
+                        button.setEnable(true);
+                    } else {
+                        button.setEnable(false);
+                    }
+                });
+            }
+        },
+
+        getCalculationValue: function () {
+            var valueObject = this.getValue();
+            var type = valueObject.type, value = valueObject.value;
+            switch (type) {
+                case BICst.MULTI_DATE_DAY_PREV:
+                    return new Date().getOffsetDate(-1 * value);
+                case BICst.MULTI_DATE_DAY_AFTER:
+                    return new Date().getOffsetDate(value);
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    return new Date();
+                case BICst.MULTI_DATE_MONTH_PREV:
+                    return new Date().getBeforeMultiMonth(value);
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                    return new Date().getAfterMultiMonth(value);
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                    return new Date(new Date().getFullYear(), new Date().getMonth(), 1);
+                case BICst.MULTI_DATE_MONTH_END:
+                    return new Date(new Date().getFullYear(), new Date().getMonth(), (new Date().getLastDateOfMonth()).getDate());
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                    return new Date().getBeforeMulQuarter(value);
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                    return new Date().getAfterMulQuarter(value);
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                    return new Date().getQuarterStartDate();
+                case BICst.MULTI_DATE_QUARTER_END:
+                    return new Date().getQuarterEndDate();
+                case BICst.MULTI_DATE_WEEK_PREV:
+                    return new Date().getOffsetDate(-7 * value);
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                    return new Date().getOffsetDate(7 * value);
+                case BICst.MULTI_DATE_YEAR_PREV:
+                    return new Date((new Date().getFullYear() - 1 * value), new Date().getMonth(), new Date().getDate());
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                    return new Date((new Date().getFullYear() + 1 * value), new Date().getMonth(), new Date().getDate());
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                    return new Date(new Date().getFullYear(), 0, 1);
+                case BICst.MULTI_DATE_YEAR_END:
+                    return new Date(new Date().getFullYear(), 11, 31);
+            }
+        }
+    });
+    BI.MultiDateCard.EVENT_CHANGE = "EVENT_CHANGE";
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.combo.js b/src/widget/multidate/multidate.combo.js
new file mode 100644
index 000000000..de00ce9b2
--- /dev/null
+++ b/src/widget/multidate/multidate.combo.js
@@ -0,0 +1,259 @@
+BICst.MULTI_DATE_YMD_CARD = 1;
+BICst.MULTI_DATE_YEAR_CARD = 2;
+BICst.MULTI_DATE_QUARTER_CARD = 3;
+BICst.MULTI_DATE_MONTH_CARD = 4;
+BICst.MULTI_DATE_WEEK_CARD = 5;
+BICst.MULTI_DATE_DAY_CARD = 6;
+BICst.MULTI_DATE_SEGMENT_NUM = {};
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV] = BI.i18nText("BI-Multi_Date_Year_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER] = BI.i18nText("BI-Multi_Date_Year_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN] = BI.i18nText("BI-Multi_Date_Year_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END] = BI.i18nText("BI-Multi_Date_Year_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV] = BI.i18nText("BI-Multi_Date_Quarter_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER] = BI.i18nText("BI-Multi_Date_Quarter_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN] = BI.i18nText("BI-Multi_Date_Quarter_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END] = BI.i18nText("BI-Multi_Date_Quarter_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV] = BI.i18nText("BI-Multi_Date_Month_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER] = BI.i18nText("BI-Multi_Date_Month_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN] = BI.i18nText("BI-Multi_Date_Month_Begin");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END] = BI.i18nText("BI-Multi_Date_Month_End");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV] = BI.i18nText("BI-Multi_Date_Week_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER] = BI.i18nText("BI-Multi_Date_Week_Next");
+
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV] = BI.i18nText("BI-Multi_Date_Day_Prev");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER] = BI.i18nText("BI-Multi_Date_Day_Next");
+BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY] = BI.i18nText("BI-Multi_Date_Today");
+
+(function ($) {
+    /**
+     * 日期控件
+     * @class BI.MultiDateCombo
+     * @extends BI.Widget
+     */
+    BI.MultiDateCombo = BI.inherit(BI.Single, {
+        constants: {
+            popupHeight: 259,
+            popupWidth: 270,
+            comboAdjustHeight: 1,
+            border: 1,
+            DATE_MIN_VALUE: "1900-01-01",
+            DATE_MAX_VALUE: "2099-12-31"
+        },
+        _defaultConfig: function () {
+            return BI.extend(BI.MultiDateCombo.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-combo',
+                height: 24
+            });
+        },
+        _init: function () {
+            BI.MultiDateCombo.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.storeTriggerValue = "";
+            var date = new Date();
+            this.storeValue = null;
+            this.trigger = BI.createWidget({
+                type: 'bi.date_trigger',
+                min: this.constants.DATE_MIN_VALUE,
+                max: this.constants.DATE_MAX_VALUE
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_KEY_DOWN, function(){
+                if(self.combo.isViewVisible()){
+                    self.combo.hideView();
+                }
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_STOP, function(){
+                if(!self.combo.isViewVisible()){
+                    self.combo.showView();
+                }
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function(){
+                self.combo.toggle();
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_FOCUS, function () {
+                self.storeTriggerValue = self.trigger.getKey();
+                if(!self.combo.isViewVisible()){
+                    self.combo.showView();
+                }
+                self.fireEvent(BI.MultiDateCombo.EVENT_FOCUS);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_ERROR, function () {
+                self.storeValue = {
+                    year: date.getFullYear(),
+                    month: date.getMonth()
+                };
+                self.popup.setValue();
+                self.fireEvent(BI.MultiDateCombo.EVENT_ERROR);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_VALID, function () {
+                self.fireEvent(BI.MultiDateCombo.EVENT_VALID);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+            });
+            this.trigger.on(BI.DateTrigger.EVENT_CONFIRM, function () {
+                if(self.combo.isViewVisible()) {
+                    return;
+                }
+                var dateStore = self.storeTriggerValue;
+                var dateObj = self.trigger.getKey();
+                if (BI.isNotEmptyString(dateObj) && !BI.isEqual(dateObj, dateStore)) {
+                    self.storeValue = self.trigger.getValue();
+                    self.setValue(self.trigger.getValue());
+                } else if (BI.isEmptyString(dateObj)) {
+                    self.storeValue = null;
+                    self.trigger.setValue();
+                }
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup = BI.createWidget({
+                type: "bi.multidate_popup",
+                min: this.constants.DATE_MIN_VALUE,
+                max: this.constants.DATE_MAX_VALUE
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE, function () {
+                self.setValue();
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE, function () {
+                var date = new Date();
+                self.setValue({
+                    year: date.getFullYear(),
+                    month: date.getMonth(),
+                    day: date.getDate()
+                });
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE, function () {
+                self.setValue(self.popup.getValue());
+                self.combo.hideView();
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.popup.on(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE, function () {
+                self.setValue(self.popup.getValue());
+                self.combo.hideView();
+                //self.fireEvent(BI.MultiDateCombo.EVENT_CHANGE);
+                self.fireEvent(BI.MultiDateCombo.EVENT_CONFIRM);
+            });
+            this.combo = BI.createWidget({
+                type: 'bi.combo',
+                toggle: false,
+                isNeedAdjustHeight: false,
+                isNeedAdjustWidth: false,
+                el: this.trigger,
+                adjustLength: this.constants.comboAdjustHeight,
+                popup: {
+                    el: this.popup,
+                    maxHeight: this.constants.popupHeight,
+                    width: this.constants.popupWidth,
+                    stopPropagation: false
+                }
+            });
+            this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+                self.popup.setValue(self.storeValue);
+                self.fireEvent(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW);
+            });
+
+            var triggerBtn = BI.createWidget({
+                type: "bi.trigger_icon_button",
+                cls: "bi-trigger-date-button chart-date-normal-font",
+                width: 30,
+                height: 23
+            });
+            triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+                if (self.combo.isViewVisible()) {
+                    self.combo.hideView();
+                } else {
+                    self.combo.showView();
+                }
+            });
+            this.changeIcon = BI.createWidget({
+                type: "bi.icon_button",
+                cls: "bi-trigger-date-change widget-date-h-change-font",
+                width: 30,
+                height: 23,
+                invisible: true
+            });
+
+
+            BI.createWidget({
+                type: "bi.absolute",
+                element: this,
+                items: [{
+                    el: this.combo,
+                    top: 0,
+                    left: 0,
+                    right: 0,
+                    bottom: 0
+                }, {
+                    el: triggerBtn,
+                    top: 0,
+                    left: 0
+                }, {
+                    el: this.changeIcon,
+                    top: 0,
+                    right: 0
+                }]
+            })
+        },
+
+        _checkDynamicValue: function(v){
+            var type = null;
+            if (BI.isNotNull(v)) {
+                type = v.type
+            }
+            switch (type){
+                case BICst.MULTI_DATE_YEAR_PREV:
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                case BICst.MULTI_DATE_YEAR_END:
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                case BICst.MULTI_DATE_QUARTER_END:
+                case BICst.MULTI_DATE_MONTH_PREV:
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                case BICst.MULTI_DATE_MONTH_END:
+                case BICst.MULTI_DATE_WEEK_PREV:
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                case BICst.MULTI_DATE_DAY_PREV:
+                case BICst.MULTI_DATE_DAY_AFTER:
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    this.changeIcon.setVisible(true);
+                    break;
+                default:
+                    this.changeIcon.setVisible(false);
+                    break;
+            }
+        },
+
+        setValue: function (v) {
+            this.storeValue = v;
+            this.popup.setValue(v);
+            this.trigger.setValue(v);
+            this._checkDynamicValue(v)
+        },
+        getValue: function () {
+            return this.storeValue;
+        },
+        getKey: function(){
+            return this.trigger.getKey();
+        },
+        hidePopupView: function () {
+            this.combo.hideView();
+        }
+    });
+    $.shortcut('bi.multidate_combo', BI.MultiDateCombo);
+
+    BI.MultiDateCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+    BI.MultiDateCombo.EVENT_FOCUS = "EVENT_FOCUS";
+    BI.MultiDateCombo.EVENT_CHANGE = "EVENT_CHANGE";
+    BI.MultiDateCombo.EVENT_VALID = "EVENT_VALID";
+    BI.MultiDateCombo.EVENT_ERROR = "EVENT_ERROR";
+    BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW = "BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW";
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.day.js b/src/widget/multidate/multidate.day.js
new file mode 100644
index 000000000..4aa18c549
--- /dev/null
+++ b/src/widget/multidate/multidate.day.js
@@ -0,0 +1,45 @@
+(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.DayCard
+     * @extends BI.MultiDateCard
+     */
+    BI.DayCard = BI.inherit(BI.MultiDateCard, {
+
+        _defaultConfig: function () {
+            return $.extend(BI.DayCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-daycard'
+            });
+        },
+
+        _init: function () {
+            BI.DayCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                isEditorExist: true,
+                selected: true,
+                text: BI.i18nText("BI-Multi_Date_Day_Prev"),
+                value: BICst.MULTI_DATE_DAY_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Day_Next"),
+                    value: BICst.MULTI_DATE_DAY_AFTER
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_DAY_TODAY,
+                    text: BI.i18nText("BI-Multi_Date_Today")
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_DAY_PREV
+        }
+    });
+    BI.DayCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.daycard', BI.DayCard);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.month.js b/src/widget/multidate/multidate.month.js
new file mode 100644
index 000000000..22d287276
--- /dev/null
+++ b/src/widget/multidate/multidate.month.js
@@ -0,0 +1,51 @@
+;
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.MonthCard
+     * @extends BI.MultiDateCard
+     */
+    BI.MonthCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.MonthCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-monthcard'
+            });
+        },
+
+        _init: function () {
+            BI.MonthCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                value: BICst.MULTI_DATE_MONTH_PREV,
+                text: BI.i18nText("BI-Multi_Date_Month_Prev")
+            },
+                {
+                    isEditorExist: true,
+                    value: BICst.MULTI_DATE_MONTH_AFTER,
+                    text: BI.i18nText("BI-Multi_Date_Month_Next")
+                },
+                {
+                    value: BICst.MULTI_DATE_MONTH_BEGIN,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Month_Begin")
+                },
+                {
+                    value: BICst.MULTI_DATE_MONTH_END,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Month_End")
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_MONTH_PREV;
+        }
+    });
+    BI.MonthCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.monthcard', BI.MonthCard);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.popup.js b/src/widget/multidate/multidate.popup.js
new file mode 100644
index 000000000..372cb0549
--- /dev/null
+++ b/src/widget/multidate/multidate.popup.js
@@ -0,0 +1,313 @@
+(function ($) {
+    /**
+     * 日期控件
+     * @class BI.MultiDatePopup
+     * @extends BI.Widget
+     */
+    BI.MultiDatePopup = BI.inherit(BI.Widget, {
+        constants: {
+            tabHeight: 30,
+            tabWidth: 42,
+            titleHeight: 27,
+            itemHeight: 30,
+            triggerHeight: 24,
+            buttonWidth: 90,
+            buttonHeight: 25,
+            cardHeight: 229,
+            cardWidth: 270,
+            popupHeight: 259,
+            popupWidth: 270,
+            comboAdjustHeight: 1,
+            ymdWidth: 58,
+            lgap: 2,
+            border: 1
+        },
+        _defaultConfig: function () {
+            return BI.extend(BI.MultiDatePopup.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-popup',
+                width: 268,
+                height: 260
+            });
+        },
+        _init: function () {
+            BI.MultiDatePopup.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.storeValue = "";
+            this.textButton = BI.createWidget({
+                type: 'bi.text_button',
+                forceCenter: true,
+                cls: 'bi-multidate-popup-label',
+                shadow: true,
+                text: BI.i18nText("BI-Multi_Date_Today")
+            });
+            this.textButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE);
+            });
+            this.clearButton = BI.createWidget({
+                type: "bi.text_button",
+                forceCenter: true,
+                cls: 'bi-multidate-popup-button',
+                shadow: true,
+                text: BI.i18nText("BI-Basic_Clear")
+            });
+            this.clearButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE);
+            });
+            this.okButton = BI.createWidget({
+                type: "bi.text_button",
+                forceCenter: true,
+                cls: 'bi-multidate-popup-button',
+                shadow: true,
+                text: BI.i18nText("BI-Basic_OK")
+            });
+            this.okButton.on(BI.TextButton.EVENT_CHANGE, function () {
+                self.fireEvent(BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE);
+            });
+            this.dateTab = BI.createWidget({
+                type: 'bi.tab',
+                tab: {
+                    cls: "bi-multidate-popup-tab",
+                    height: this.constants.tabHeight,
+                    items: BI.createItems([{
+                        text: BI.i18nText("BI-Multi_Date_YMD"),
+                        value: BICst.MULTI_DATE_YMD_CARD,
+                        width: this.constants.ymdWidth
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Year"),
+                        value: BICst.MULTI_DATE_YEAR_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Quarter"),
+                        value: BICst.MULTI_DATE_QUARTER_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Month"),
+                        value: BICst.MULTI_DATE_MONTH_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Week"),
+                        value: BICst.MULTI_DATE_WEEK_CARD
+                    }, {
+                        text: BI.i18nText("BI-Multi_Date_Day"),
+                        value: BICst.MULTI_DATE_DAY_CARD
+                    }], {
+                        width: this.constants.tabWidth,
+                        textAlign: "center",
+                        height: this.constants.itemHeight,
+                        cls: 'bi-multidate-popup-item'
+                    }),
+                    layouts: [{
+                        type: 'bi.left'
+                    }]
+                },
+                cardCreator: function (v) {
+                    switch (v) {
+                        case BICst.MULTI_DATE_YMD_CARD:
+                            self.ymd = BI.createWidget({
+                                type: "bi.date_calendar_popup",
+                                min: self.options.min,
+                                max: self.options.max
+                            });
+                            self.ymd.on(BI.DateCalendarPopup.EVENT_CHANGE, function () {
+                                self.fireEvent(BI.MultiDatePopup.CALENDAR_EVENT_CHANGE);
+                            });
+                            return self.ymd;
+                        case BICst.MULTI_DATE_YEAR_CARD:
+                            self.year = BI.createWidget({
+                                type: "bi.yearcard"
+                            });
+                            self.year.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.year, v);
+                            });
+                            return self.year;
+                        case BICst.MULTI_DATE_QUARTER_CARD:
+                            self.quarter = BI.createWidget({
+                                type: 'bi.quartercard'
+                            });
+                            self.quarter.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.quarter, v);
+                            });
+                            return self.quarter;
+                        case BICst.MULTI_DATE_MONTH_CARD:
+                            self.month = BI.createWidget({
+                                type: 'bi.monthcard'
+                            });
+                            self.month.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.month, v);
+                            });
+                            return self.month;
+                        case BICst.MULTI_DATE_WEEK_CARD:
+                            self.week = BI.createWidget({
+                                type: 'bi.weekcard'
+                            });
+                            self.week.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.week, v);
+                            });
+                            return self.week;
+                        case BICst.MULTI_DATE_DAY_CARD:
+                            self.day = BI.createWidget({
+                                type: 'bi.daycard'
+                            });
+                            self.day.on(BI.MultiDateCard.EVENT_CHANGE, function (v) {
+                                self._setInnerValue(self.day, v);
+                            });
+                            return self.day;
+                    }
+                }
+            });
+            this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+            this.cur = BICst.MULTI_DATE_YMD_CARD;
+            this.dateTab.on(BI.Tab.EVENT_CHANGE, function () {
+                var v = self.dateTab.getSelect();
+                switch (v) {
+                    case BICst.MULTI_DATE_YMD_CARD:
+                        var date = this.getTab(self.cur).getCalculationValue();
+                        self.ymd.setValue({
+                            year: date.getFullYear(),
+                            month: date.getMonth(),
+                            day: date.getDate()
+                        });
+                        self._setInnerValue(self.ymd);
+                        break;
+                    case BICst.MULTI_DATE_YEAR_CARD:
+                        self.year.setValue(self.storeValue);
+                        self._setInnerValue(self.year);
+                        break;
+                    case BICst.MULTI_DATE_QUARTER_CARD:
+                        self.quarter.setValue(self.storeValue);
+                        self._setInnerValue(self.quarter);
+                        break;
+                    case BICst.MULTI_DATE_MONTH_CARD:
+                        self.month.setValue(self.storeValue);
+                        self._setInnerValue(self.month);
+                        break;
+                    case BICst.MULTI_DATE_WEEK_CARD:
+                        self.week.setValue(self.storeValue);
+                        self._setInnerValue(self.week);
+                        break;
+                    case BICst.MULTI_DATE_DAY_CARD:
+                        self.day.setValue(self.storeValue);
+                        self._setInnerValue(self.day);
+                        break;
+                }
+                self.cur = v;
+            });
+            this.dateButton = BI.createWidget({
+                type: "bi.grid",
+                items: [[this.clearButton, this.textButton, this.okButton]]
+            });
+            BI.createWidget({
+                element: this,
+                type: "bi.vtape",
+                items: [{
+                    el: this.dateTab
+                }, {
+                    el: this.dateButton,
+                    height: 30
+                }]
+            });
+        },
+        _setInnerValue: function (obj) {
+            if (this.dateTab.getSelect() === BICst.MULTI_DATE_YMD_CARD) {
+                this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                this.textButton.setEnable(true);
+            } else {
+                var date = obj.getCalculationValue();
+                date = date.print("%Y-%x-%e");
+                this.textButton.setValue(date);
+                this.textButton.setEnable(false);
+            }
+        },
+        setValue: function (v) {
+            this.storeValue = v;
+            var self = this, date;
+            var type, value;
+            if (BI.isNotNull(v)) {
+                type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value;
+                if(BI.isNull(value)){
+                    value = v;
+                }
+            }
+            switch (type) {
+                case BICst.MULTI_DATE_YEAR_PREV:
+                case BICst.MULTI_DATE_YEAR_AFTER:
+                case BICst.MULTI_DATE_YEAR_BEGIN:
+                case BICst.MULTI_DATE_YEAR_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_YEAR_CARD);
+                    this.year.setValue({type: type, value: value});
+                    this.cur = BICst.MULTI_DATE_YEAR_CARD;
+                    self._setInnerValue(this.year);
+                    break;
+                case BICst.MULTI_DATE_QUARTER_PREV:
+                case BICst.MULTI_DATE_QUARTER_AFTER:
+                case BICst.MULTI_DATE_QUARTER_BEGIN:
+                case BICst.MULTI_DATE_QUARTER_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_QUARTER_CARD);
+                    this.cur = BICst.MULTI_DATE_QUARTER_CARD;
+                    this.quarter.setValue({type: type, value: value});
+                    self._setInnerValue(this.quarter);
+                    break;
+                case BICst.MULTI_DATE_MONTH_PREV:
+                case BICst.MULTI_DATE_MONTH_AFTER:
+                case BICst.MULTI_DATE_MONTH_BEGIN:
+                case BICst.MULTI_DATE_MONTH_END:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_MONTH_CARD);
+                    this.cur = BICst.MULTI_DATE_MONTH_CARD;
+                    this.month.setValue({type: type, value: value});
+                    self._setInnerValue(this.month);
+                    break;
+                case BICst.MULTI_DATE_WEEK_PREV:
+                case BICst.MULTI_DATE_WEEK_AFTER:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_WEEK_CARD);
+                    this.cur = BICst.MULTI_DATE_WEEK_CARD;
+                    this.week.setValue({type: type, value: value});
+                    self._setInnerValue(this.week);
+                    break;
+                case BICst.MULTI_DATE_DAY_PREV:
+                case BICst.MULTI_DATE_DAY_AFTER:
+                case BICst.MULTI_DATE_DAY_TODAY:
+                    this.dateTab.setSelect(BICst.MULTI_DATE_DAY_CARD);
+                    this.cur = BICst.MULTI_DATE_DAY_CARD;
+                    this.day.setValue({type: type, value: value});
+                    self._setInnerValue(this.day);
+                    break;
+                default:
+                    if (BI.isNull(value) || BI.isEmptyObject(value)) {
+                        var date = new Date();
+                        this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+                        this.ymd.setValue({
+                            year: date.getFullYear(),
+                            month: date.getMonth(),
+                            day: date.getDate()
+                        });
+                        this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                    } else {
+                        this.dateTab.setSelect(BICst.MULTI_DATE_YMD_CARD);
+                        this.ymd.setValue(value);
+                        this.textButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
+                    }
+                    this.textButton.setEnable(true);
+                    break;
+            }
+        },
+        getValue: function () {
+            var tab = this.dateTab.getSelect();
+            switch (tab) {
+                case BICst.MULTI_DATE_YMD_CARD:
+                    return this.ymd.getValue();
+                case BICst.MULTI_DATE_YEAR_CARD:
+                    return this.year.getValue();
+                case BICst.MULTI_DATE_QUARTER_CARD:
+                    return this.quarter.getValue();
+                case BICst.MULTI_DATE_MONTH_CARD:
+                    return this.month.getValue();
+                case BICst.MULTI_DATE_WEEK_CARD:
+                    return this.week.getValue();
+                case BICst.MULTI_DATE_DAY_CARD:
+                    return this.day.getValue();
+            }
+        }
+    });
+    BI.MultiDatePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE";
+    BI.MultiDatePopup.BUTTON_lABEL_EVENT_CHANGE = "BUTTON_lABEL_EVENT_CHANGE";
+    BI.MultiDatePopup.BUTTON_CLEAR_EVENT_CHANGE = "BUTTON_CLEAR_EVENT_CHANGE";
+    BI.MultiDatePopup.CALENDAR_EVENT_CHANGE = "CALENDAR_EVENT_CHANGE";
+    $.shortcut('bi.multidate_popup', BI.MultiDatePopup);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.quarter.js b/src/widget/multidate/multidate.quarter.js
new file mode 100644
index 000000000..26a11599e
--- /dev/null
+++ b/src/widget/multidate/multidate.quarter.js
@@ -0,0 +1,51 @@
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.QuarterCard
+     * @extends BI.MultiDateCard
+     */
+    BI.QuarterCard = BI.inherit(BI.MultiDateCard, {
+
+        _defaultConfig: function () {
+            return $.extend(BI.QuarterCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-quartercard'
+            });
+        },
+
+        _init: function () {
+            BI.QuarterCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                value: BICst.MULTI_DATE_QUARTER_PREV,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Quarter_Prev")
+            },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_AFTER,
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_Next")
+                },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_BEGIN,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_Begin")
+                },
+                {
+                    value: BICst.MULTI_DATE_QUARTER_END,
+                    isEditorExist: false,
+                    text: BI.i18nText("BI-Multi_Date_Quarter_End")
+                }]
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_QUARTER_PREV;
+        }
+    });
+    BI.QuarterCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.quartercard', BI.QuarterCard);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.segment.js b/src/widget/multidate/multidate.segment.js
new file mode 100644
index 000000000..f22d6f375
--- /dev/null
+++ b/src/widget/multidate/multidate.segment.js
@@ -0,0 +1,134 @@
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.MultiDateSegment
+     * @extends BI.Single
+     */
+    BI.MultiDateSegment = BI.inherit(BI.Single, {
+        constants: {
+            itemHeight: 24,
+            maxGap: 15,
+            minGap: 10,
+            textWidth: 30,
+            defaultEditorValue: "1"
+        },
+
+        _defaultConfig: function () {
+            return $.extend(BI.MultiDateSegment.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-segment',
+                text: "",
+                width: 130,
+                height: 30,
+                isEditorExist: true,
+                selected: false,
+                defaultEditorValue: "1"
+            });
+        },
+
+        _init: function () {
+            BI.MultiDateSegment.superclass._init.apply(this, arguments);
+            var self = this, opts = this.options;
+            this.radio = BI.createWidget({
+                type: "bi.radio",
+                selected: opts.selected
+            });
+            this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            this.textEditor = BI.createWidget({
+                type: 'bi.text_editor',
+                value: this.constants.defaultEditorValue,
+                title:this.constants.defaultEditorValue,
+                cls: 'bi-multidate-editor',
+                width: this.constants.textWidth,
+                height: this.constants.itemHeight
+            });
+            this.textEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+                self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            });
+            this.textEditor.on(BI.TextEditor.EVENT_CONFIRM, function () {
+                this.setTitle(this.getValue());
+            });
+            this.text = BI.createWidget({
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'bi-multidate-normal-label',
+                text: opts.text,
+                height: this.constants.itemHeight
+            });
+            this._createSegment();
+        },
+        _createSegment: function () {
+            if (this.options.isEditorExist === true) {
+                return BI.createWidget({
+                    element: this,
+                    type: 'bi.left',
+                    items: [{
+                        el: {
+                            type: "bi.center_adapt",
+                            items: [this.radio],
+                            height: this.constants.itemHeight
+                        },
+                        lgap: 0
+                    },
+                        {
+                            el: {
+                                type: "bi.center_adapt",
+                                items: [this.textEditor],
+                                widgetName: 'textEditor'
+                            },
+                            lgap: this.constants.maxGap
+                        },
+                        {
+                            el: this.text,
+                            lgap: this.constants.minGap
+                        }]
+                });
+            }
+            return BI.createWidget({
+                element: this,
+                type: 'bi.left',
+                items: [{
+                    el: {
+                        type: "bi.center_adapt",
+                        items: [this.radio],
+                        height: this.constants.itemHeight
+                    },
+                    lgap: 0
+                },
+                    {
+                        el: this.text,
+                        lgap: this.constants.maxGap
+                    }]
+            })
+        },
+        setSelected: function (v) {
+            if (BI.isNotNull(this.radio)) {
+                this.radio.setSelected(v);
+            }
+        },
+        isSelected: function () {
+            return this.radio.isSelected();
+        },
+        getValue: function () {
+            return this.options.value;
+        },
+        getInputValue: function () {
+            return this.textEditor.getValue() | 0;
+        },
+        setInputValue: function (v) {
+            this.textEditor.setValue(v);
+        },
+        isEditorExist: function () {
+            return this.options.isEditorExist;
+        },
+        setEnable: function (b) {
+            BI.Editor.superclass.setEnable.apply(this, arguments);
+            this.textEditor && this.textEditor.setEnable(b);
+        }
+    });
+    BI.MultiDateSegment.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.multidate_segment', BI.MultiDateSegment);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.week.js b/src/widget/multidate/multidate.week.js
new file mode 100644
index 000000000..1546782c5
--- /dev/null
+++ b/src/widget/multidate/multidate.week.js
@@ -0,0 +1,41 @@
+;
+(function ($) {
+
+    /**
+     * 普通控件
+     *
+     * @class BI.WeekCard
+     * @extends BI.MultiDateCard
+     */
+    BI.WeekCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.WeekCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-weekcard'
+            });
+        },
+
+        _init: function () {
+            BI.WeekCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Week_Prev"),
+                value: BICst.MULTI_DATE_WEEK_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Week_Next"),
+                    value: BICst.MULTI_DATE_WEEK_AFTER
+                }];
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_WEEK_PREV;
+        }
+    });
+    BI.WeekCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.weekcard', BI.WeekCard);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multidate/multidate.year.js b/src/widget/multidate/multidate.year.js
new file mode 100644
index 000000000..03021ac36
--- /dev/null
+++ b/src/widget/multidate/multidate.year.js
@@ -0,0 +1,49 @@
+(function ($) {
+    /**
+     * 普通控件
+     *
+     * @class BI.YearCard
+     * @extends BI.MultiDateCard
+     */
+    BI.YearCard = BI.inherit(BI.MultiDateCard, {
+        _defaultConfig: function () {
+            return $.extend(BI.YearCard.superclass._defaultConfig.apply(this, arguments), {
+                baseCls: 'bi-multidate-yearcard'
+            });
+        },
+
+        _init: function () {
+            BI.YearCard.superclass._init.apply(this, arguments);
+        },
+
+        dateConfig: function(){
+            return [{
+                selected: true,
+                isEditorExist: true,
+                text: BI.i18nText("BI-Multi_Date_Year_Prev"),
+                value: BICst.MULTI_DATE_YEAR_PREV
+            },
+                {
+                    isEditorExist: true,
+                    text: BI.i18nText("BI-Multi_Date_Year_Next"),
+                    value: BICst.MULTI_DATE_YEAR_AFTER
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_YEAR_BEGIN,
+                    text: BI.i18nText("BI-Multi_Date_Year_Begin")
+                },
+                {
+                    isEditorExist: false,
+                    value: BICst.MULTI_DATE_YEAR_END,
+                    text: BI.i18nText("BI-Multi_Date_Year_End")
+                }]
+        },
+
+        defaultSelectedItem: function(){
+            return BICst.MULTI_DATE_YEAR_PREV;
+        }
+    });
+    BI.YearCard.EVENT_CHANGE = "EVENT_CHANGE";
+    $.shortcut('bi.yearcard', BI.YearCard);
+})(jQuery);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/multilayerselecttree.combo.js b/src/widget/multilayerselecttree/multilayerselecttree.combo.js
new file mode 100644
index 000000000..d6ece4c7a
--- /dev/null
+++ b/src/widget/multilayerselecttree/multilayerselecttree.combo.js
@@ -0,0 +1,70 @@
+/**
+ * @class BI.MultiLayerSelectTreeCombo
+ * @extends BI.Widget
+ */
+BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer_select_tree-combo",
+            isDefaultInit: false,
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.multilayer_select_tree_popup",
+            isDefaultInit: o.isDefaultInit,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.MultiLayerSelectTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MultiLayerSelectTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+BI.MultiLayerSelectTreeCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_select_tree_combo", BI.MultiLayerSelectTreeCombo);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js b/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js
new file mode 100644
index 000000000..363aacf29
--- /dev/null
+++ b/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js
@@ -0,0 +1,132 @@
+/**
+ * guy
+ * 二级树
+ * @class BI.MultiLayerSelectLevelTree
+ * @extends BI.Select
+ */
+BI.MultiLayerSelectLevelTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectLevelTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-select-level-tree",
+            isDefaultInit: false,
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectLevelTree.superclass._init.apply(this, arguments);
+
+        this.initTree(this.options.items);
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {};
+            node.layer = layer;
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.multilayer_select_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.multilayer_select_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_select_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+
+                self._formatItems(node.children, layer + 1);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.multilayer_single_tree_last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _assertId: function (sNodes) {
+        BI.each(sNodes, function (i, node) {
+            node.id = node.id || BI.UUID();
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.empty();
+        this._assertId(nodes);
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: {
+                type: "bi.select_tree_expander",
+                isDefaultInit: o.isDefaultInit,
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            },
+
+            items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0),
+            itemsCreator: o.itemsCreator,
+
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.Single,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+
+    populate: function (nodes) {
+        this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0));
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    getAllLeaves: function () {
+        return this.tree.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree.getNodeByValue(id);
+    }
+});
+BI.MultiLayerSelectLevelTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multilayer_select_level_tree", BI.MultiLayerSelectLevelTree);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/multilayerselecttree.popup.js b/src/widget/multilayerselecttree/multilayerselecttree.popup.js
new file mode 100644
index 000000000..00644df62
--- /dev/null
+++ b/src/widget/multilayerselecttree/multilayerselecttree.popup.js
@@ -0,0 +1,67 @@
+/**
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSelectTreePopup
+ * @extends BI.Pane
+ */
+
+BI.MultiLayerSelectTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSelectTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-select-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            isDefaultInit: false,
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSelectTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.multilayer_select_level_tree',
+            isDefaultInit: o.isDefaultInit,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            scrollable: true,
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiLayerSelectTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.MultiLayerSelectTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.MultiLayerSelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_select_tree_popup", BI.MultiLayerSelectTreePopup);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/node/node.first.plus.js b/src/widget/multilayerselecttree/node/node.first.plus.js
new file mode 100644
index 000000000..f950c090c
--- /dev/null
+++ b/src/widget/multilayerselecttree/node/node.first.plus.js
@@ -0,0 +1,94 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-first-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_first_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_first_plus_group_node", BI.MultiLayerSelectTreeFirstPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/node/node.last.plus.js b/src/widget/multilayerselecttree/node/node.last.plus.js
new file mode 100644
index 000000000..f596f4c70
--- /dev/null
+++ b/src/widget/multilayerselecttree/node/node.last.plus.js
@@ -0,0 +1,90 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-last-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_last_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_last_plus_group_node", BI.MultiLayerSelectTreeLastPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayerselecttree/node/node.mid.plus.js b/src/widget/multilayerselecttree/node/node.mid.plus.js
new file mode 100644
index 000000000..5c8593b57
--- /dev/null
+++ b/src/widget/multilayerselecttree/node/node.mid.plus.js
@@ -0,0 +1,90 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSelectTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-select-tree-mid-plus-group-node bi-list-item-active",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.select_tree_mid_plus_group_node",
+            stopPropagation: true,
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.setSelected(self.isSelected());
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    isSelected: function () {
+        return this.node.isSelected();
+    },
+
+    setSelected: function (b) {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setSelected.apply(this, arguments);
+        this.node.setSelected(b);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        this.node.setOpened(v);
+    }
+});
+
+$.shortcut("bi.multilayer_select_tree_mid_plus_group_node", BI.MultiLayerSelectTreeMidPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/multilayersingletree.combo.js b/src/widget/multilayersingletree/multilayersingletree.combo.js
new file mode 100644
index 000000000..f6ccaf941
--- /dev/null
+++ b/src/widget/multilayersingletree/multilayersingletree.combo.js
@@ -0,0 +1,75 @@
+/**
+ * 多层级下拉单选树
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSingleTreeCombo
+ * @extends BI.Widget
+ */
+BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-singletree-combo",
+            isDefaultInit: false,
+            height: 30,
+            text: "",
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.multilayer_single_tree_popup",
+            isDefaultInit: o.isDefaultInit,
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.MultiLayerSingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.MultiLayerSingleTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+
+BI.MultiLayerSingleTreeCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_single_tree_combo", BI.MultiLayerSingleTreeCombo);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/multilayersingletree.leveltree.js b/src/widget/multilayersingletree/multilayersingletree.leveltree.js
new file mode 100644
index 000000000..93c25b2b5
--- /dev/null
+++ b/src/widget/multilayersingletree/multilayersingletree.leveltree.js
@@ -0,0 +1,135 @@
+/**
+ * guy
+ * 二级树
+ * @class BI.MultiLayerSingleLevelTree
+ * @extends BI.Single
+ */
+BI.MultiLayerSingleLevelTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleLevelTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-single-level-tree",
+            isDefaultInit: false,
+            items: [],
+            itemsCreator: BI.emptyFn
+        })
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleLevelTree.superclass._init.apply(this, arguments);
+
+        this.initTree(this.options.items);
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {};
+            node.layer = layer;
+            if (!BI.isKey(node.id)) {
+                node.id = BI.UUID();
+            }
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.multilayer_single_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.multilayer_single_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+
+                self._formatItems(node.children, layer + 1);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.multilayer_single_tree_last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _assertId: function (sNodes) {
+        BI.each(sNodes, function (i, node) {
+            node.id = node.id || BI.UUID();
+        });
+    },
+
+    //构造树结构,
+    initTree: function (nodes) {
+        var self = this, o = this.options;
+        this.empty();
+        this._assertId(nodes);
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: {
+                isDefaultInit: o.isDefaultInit,
+                el: {},
+                popup: {
+                    type: "bi.custom_tree"
+                }
+            },
+
+            items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0),
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (items) {
+                    callback(BI.Tree.transformToTreeFormat(items), 0)
+                })
+            },
+
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.Single,
+                layouts: [{
+                    type: "bi.vertical"
+                }]
+            }
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, arguments);
+            }
+        })
+    },
+
+    populate: function (nodes) {
+        this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0));
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    getAllLeaves: function () {
+        return this.tree.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.tree.getNodeById(id);
+    },
+
+    getNodeByValue: function (id) {
+        return this.tree.getNodeByValue(id);
+    }
+});
+BI.MultiLayerSingleLevelTree.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multilayer_single_level_tree", BI.MultiLayerSingleLevelTree);
diff --git a/src/widget/multilayersingletree/multilayersingletree.popup.js b/src/widget/multilayersingletree/multilayersingletree.popup.js
new file mode 100644
index 000000000..1411587be
--- /dev/null
+++ b/src/widget/multilayersingletree/multilayersingletree.popup.js
@@ -0,0 +1,67 @@
+/**
+ * Created by GUY on 2016/1/26.
+ *
+ * @class BI.MultiLayerSingleTreePopup
+ * @extends BI.Pane
+ */
+
+BI.MultiLayerSingleTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multilayer-singletree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            isDefaultInit: false,
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.MultiLayerSingleTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.multilayer_single_level_tree',
+            isDefaultInit: o.isDefaultInit,
+            items: o.items,
+            itemsCreator: o.itemsCreator
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrolly: false,
+            scrollable: true,
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiLayerSingleTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.MultiLayerSingleTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.MultiLayerSingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.multilayer_single_tree_popup", BI.MultiLayerSingleTreePopup);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/node/node.first.plus.js b/src/widget/multilayersingletree/node/node.first.plus.js
new file mode 100644
index 000000000..dea6ce89c
--- /dev/null
+++ b/src/widget/multilayersingletree/node/node.first.plus.js
@@ -0,0 +1,83 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-first-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.first_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_first_plus_group_node", BI.MultiLayerSingleTreeFirstPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/node/node.last.plus.js b/src/widget/multilayersingletree/node/node.last.plus.js
new file mode 100644
index 000000000..123aa1d14
--- /dev/null
+++ b/src/widget/multilayersingletree/node/node.last.plus.js
@@ -0,0 +1,83 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-last-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.last_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_last_plus_group_node", BI.MultiLayerSingleTreeLastPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/node/node.mid.plus.js b/src/widget/multilayersingletree/node/node.mid.plus.js
new file mode 100644
index 000000000..c5ca0fb92
--- /dev/null
+++ b/src/widget/multilayersingletree/node/node.mid.plus.js
@@ -0,0 +1,83 @@
+/**
+ * 加号表示的组节点
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.MultiLayerSingleTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-multilayer-single-tree-mid-plus-group-node bi-list-item",
+            layer: 0,//第几层级
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.node = BI.createWidget({
+            type: "bi.mid_plus_group_node",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            open: o.open,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.node.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.node);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.node.doRedMark.apply(this.node, arguments);
+    },
+
+    unRedMark: function () {
+        this.node.unRedMark.apply(this.node, arguments);
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments);
+        this.node.setSelected(this.isSelected());
+    },
+
+    setOpened: function (v) {
+        BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.node)) {
+            this.node.setOpened(v);
+        }
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_mid_plus_group_node", BI.MultiLayerSingleTreeMidPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/treeitem/item.first.treeleaf.js b/src/widget/multilayersingletree/treeitem/item.first.treeleaf.js
new file mode 100644
index 000000000..57d79311b
--- /dev/null
+++ b/src/widget/multilayersingletree/treeitem/item.first.treeleaf.js
@@ -0,0 +1,96 @@
+/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeFirstTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeFirstTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-first-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.first_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_first_tree_leaf_item", BI.MultiLayerSingleTreeFirstTreeLeafItem);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/treeitem/item.last.treeleaf.js b/src/widget/multilayersingletree/treeitem/item.last.treeleaf.js
new file mode 100644
index 000000000..9560f8d19
--- /dev/null
+++ b/src/widget/multilayersingletree/treeitem/item.last.treeleaf.js
@@ -0,0 +1,96 @@
+/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeLastTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeLastTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-last-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.last_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_last_tree_leaf_item", BI.MultiLayerSingleTreeLastTreeLeafItem);
\ No newline at end of file
diff --git a/src/widget/multilayersingletree/treeitem/item.mid.treeleaf.js b/src/widget/multilayersingletree/treeitem/item.mid.treeleaf.js
new file mode 100644
index 000000000..1cc73b220
--- /dev/null
+++ b/src/widget/multilayersingletree/treeitem/item.mid.treeleaf.js
@@ -0,0 +1,96 @@
+/**
+ *
+ * Created by GUY on 2016/1/27.
+ * @class BI.MultiLayerSingleTreeMidTreeLeafItem
+ * @extends BI.BasicButton
+ */
+BI.MultiLayerSingleTreeMidTreeLeafItem = BI.inherit(BI.BasicButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-multilayer-single-tree-mid-tree-leaf-item bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            layer: 0,
+            id: "",
+            pId: "",
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.item = BI.createWidget({
+            type: "bi.mid_tree_leaf_item",
+            logic: {
+                dynamic: true
+            },
+            id: o.id,
+            pId: o.pId,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.item.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {//本身实现click功能
+                return;
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        var items = [];
+        BI.count(0, o.layer, function () {
+            items.push({
+                type: "bi.layout",
+                cls: "base-line-conn-background",
+                width: 13,
+                height: o.height
+            })
+        });
+        items.push(this.item);
+        BI.createWidget({
+            type: "bi.td",
+            element: this,
+            columnSize: BI.makeArray(o.layer, 13),
+            items: [items]
+        })
+    },
+
+    doRedMark: function () {
+        this.item.doRedMark.apply(this.item, arguments);
+    },
+
+    unRedMark: function () {
+        this.item.unRedMark.apply(this.item, arguments);
+    },
+
+    doHighLight: function () {
+        this.item.doHighLight.apply(this.item, arguments);
+    },
+
+    unHighLight: function () {
+        this.item.unHighLight.apply(this.item, arguments);
+    },
+
+    getId: function () {
+        return this.options.id;
+    },
+
+    getPId: function () {
+        return this.options.pId;
+    },
+
+    doClick: function () {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.doClick.apply(this, arguments);
+        this.item.setSelected(this.isSelected());
+    },
+
+    setSelected: function (v) {
+        BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.setSelected.apply(this, arguments);
+        this.item.setSelected(v);
+    }
+});
+
+$.shortcut("bi.multilayer_single_tree_mid_tree_leaf_item", BI.MultiLayerSingleTreeMidTreeLeafItem);
\ No newline at end of file
diff --git a/src/widget/multiselect/check/multiselect.check.pane.js b/src/widget/multiselect/check/multiselect.check.pane.js
new file mode 100644
index 000000000..2286b38ba
--- /dev/null
+++ b/src/widget/multiselect/check/multiselect.check.pane.js
@@ -0,0 +1,107 @@
+/**
+ *
+ * @class BI.MultiSelectCheckPane
+ * @extends BI.Widget
+ */
+BI.MultiSelectCheckPane = BI.inherit(BI.Widget, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-check-pane",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            onClickContinueSelect: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.storeValue = {};
+        this.display = BI.createWidget({
+            type: 'bi.display_selected_list',
+            items: opts.items,
+            itemsCreator: function (op, callback) {
+                op = BI.extend(op || {}, {
+                    selected_values: self.storeValue.value
+                });
+                if (self.storeValue.type === BI.Selection.Multi) {
+                    callback({
+                        items: BI.map(self.storeValue.value, function (i, v) {
+                            var txt = opts.valueFormatter(v) || v;
+                            return {
+                                text: txt,
+                                value: v,
+                                title: txt
+                            }
+                        })
+                    });
+                    return;
+                }
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.continueSelect = BI.createWidget({
+            type: 'bi.text_button',
+            text: BI.i18nText('BI-Continue_Select'),
+            cls: 'multi-select-check-selected'
+        });
+
+        this.continueSelect.on(BI.TextButton.EVENT_CHANGE, function () {
+            opts.onClickContinueSelect();
+        });
+
+        BI.createWidget({
+            type: 'bi.vtape',
+            element: this,
+            items: [{
+                height: this.constants.height,
+                el: {
+                    type: 'bi.left',
+                    cls: 'multi-select-continue-select',
+                    items: [
+                        {
+                            el: {
+                                type: "bi.label",
+                                text: BI.i18nText('BI-Selected_Data')
+                            },
+                            lgap: this.constants.lgap,
+                            tgap: this.constants.tgap
+                        },
+                        {
+                            el: this.continueSelect,
+                            lgap: this.constants.lgap,
+                            tgap: this.constants.tgap
+                        }]
+                }
+            }, {
+                height: 'fill',
+                el: this.display
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+    },
+
+    empty: function () {
+        this.display.empty();
+    },
+
+    populate: function () {
+        this.display.populate.apply(this.display, arguments);
+    }
+});
+
+$.shortcut("bi.multi_select_check_pane", BI.MultiSelectCheckPane);
\ No newline at end of file
diff --git a/src/widget/multiselect/check/multiselect.display.js b/src/widget/multiselect/check/multiselect.display.js
new file mode 100644
index 000000000..4eb4fe42c
--- /dev/null
+++ b/src/widget/multiselect/check/multiselect.display.js
@@ -0,0 +1,87 @@
+/**
+ *
+ *
+ * 查看已选弹出层的展示面板
+ * @class BI.DisplaySelectedList
+ * @extends BI.Widget
+ */
+BI.DisplaySelectedList = BI.inherit(BI.Pane, {
+
+    constants: {
+        height: 25,
+        lgap: 10
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DisplaySelectedList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-display-list",
+            itemsCreator: BI.emptyFn,
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.DisplaySelectedList.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.list_pane",
+            element: this,
+            el: {
+                type: "bi.loader",
+                isDefaultInit: false,
+                logic: {
+                    dynamic: true,
+                    scrolly: true
+                },
+                items: this._createItems(opts.items),
+                chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                layouts: [{
+                    type: "bi.vertical",
+                    lgap: 10
+                }]
+            },
+            itemsCreator: function (options, callback) {
+
+                opts.itemsCreator(options, function (ob) {
+                    self.hasNext = !!ob.hasNext;
+                    callback(self._createItems(ob.items));
+                })
+            },
+            hasNext: function () {
+                return self.hasNext;
+            }
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: 'bi.icon_text_item',
+            cls: 'cursor-default check-font display-list-item',
+            once: true,
+            invalid: true,
+            selected: true,
+            height: this.constants.height,
+            logic: {
+                dynamic: true
+            }
+        });
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        if (arguments.length === 0) {
+            this.button_group.populate();
+        } else {
+            this.button_group.populate(this._createItems(items));
+        }
+    }
+});
+
+$.shortcut('bi.display_selected_list', BI.DisplaySelectedList);
\ No newline at end of file
diff --git a/src/widget/multiselect/multiselect.combo.js b/src/widget/multiselect/multiselect.combo.js
new file mode 100644
index 000000000..e1424daa4
--- /dev/null
+++ b/src/widget/multiselect/multiselect.combo.js
@@ -0,0 +1,348 @@
+/**
+ *
+ * @class BI.MultiSelectCombo
+ * @extends BI.Single
+ */
+BI.MultiSelectCombo = BI.inherit(BI.Single, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-combo',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            height: 28
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        var assertShowValue = function () {
+            BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue);
+            self.trigger.getSearcher().setState(self.storeValue);
+            self.trigger.getCounter().setButtonChecked(self.storeValue);
+        };
+        this.storeValue = {};
+        this.popup = BI.createWidget({
+            type: 'bi.multi_select_popup_view',
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            onLoaded: function () {
+                BI.nextTick(function () {
+                    self.combo.adjustWidth();
+                    self.combo.adjustHeight();
+                    self.trigger.getCounter().adjustView();
+                    self.trigger.getSearcher().adjustView();
+                });
+            }
+        });
+
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CHANGE, function () {
+            self.storeValue = this.getValue();
+            self._adjust(function () {
+                assertShowValue();
+            });
+        });
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM, function () {
+            self._defaultState();
+        });
+        this.popup.on(BI.MultiSelectPopupView.EVENT_CLICK_CLEAR, function () {
+            self.setValue();
+            self._defaultState();
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: {
+                    left: 1,
+                    top: 1,
+                    right: 2,
+                    bottom: 33
+                }
+            },
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (res) {
+                    if (op.times === 1 && BI.isNotNull(op.keywords)) {
+                        self.trigger.setValue(self.getValue());
+                    }
+                    callback.apply(self, arguments);
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self._setStartValue("");
+            this.getSearcher().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self._setStartValue("");
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_PAUSE, function () {
+            if (this.getSearcher().hasMatched()) {
+                var keyword = this.getSearcher().getKeyword();
+                self._join({
+                    type: BI.Selection.Multi,
+                    value: [keyword]
+                }, function () {
+                    self.combo.setValue(self.storeValue);
+                    self._setStartValue(keyword);
+                    assertShowValue();
+                    self.populate();
+                    self._setStartValue("");
+                })
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_SEARCHING, function (keywords) {
+            var last = BI.last(keywords);
+            keywords = BI.initial(keywords || []);
+            if (keywords.length > 0) {
+                self._joinKeywords(keywords, function () {
+                    if (BI.isEndWithBlank(last)) {
+                        self.combo.setValue(self.storeValue);
+                        assertShowValue();
+                        self.combo.populate();
+                        self._setStartValue("");
+                    } else {
+                        self.combo.setValue(self.storeValue);
+                        assertShowValue();
+                    }
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function (value, obj) {
+            if (obj instanceof BI.MultiSelectBar) {
+                self._joinAll(this.getValue(), function () {
+                    assertShowValue();
+                });
+            } else {
+                self._join(this.getValue(), function () {//安徽省 北京
+                    assertShowValue();
+                });
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            this.getCounter().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: this.popup
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            this.setValue(self.storeValue);
+            BI.nextTick(function () {
+                self.populate();
+            });
+        });
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            //important:关闭弹出时又可能没有退出编辑状态
+            self.trigger.stopEditing();
+            self.fireEvent(BI.MultiSelectCombo.EVENT_CONFIRM);
+        });
+
+        var triggerBtn = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: o.height,
+            height: o.height,
+            cls: "multi-select-trigger-icon-button"
+        });
+        triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+            self.trigger.getCounter().hideView();
+            if (self.combo.isViewVisible()) {
+                self.combo.hideView();
+            } else {
+                self.combo.showView();
+            }
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: triggerBtn,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+        this.combo.hideView();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    _makeMap: function (values) {
+        return BI.makeObject(values || []);
+    },
+
+    _joinKeywords: function (keywords, callback) {
+        var self = this, o = this.options;
+        this._assertValue(this.storeValue);
+        o.itemsCreator({
+            type: BI.MultiSelectCombo.REQ_GET_ALL_DATA,
+            keywords: keywords
+        }, function (ob) {
+            var values = BI.pluck(ob.items, "value");
+            digest(values);
+        });
+
+        function digest(items) {
+            var selectedMap = self._makeMap(items);
+            BI.each(keywords, function (i, val) {
+                if (BI.isNotNull(selectedMap[val])) {
+                    self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val);
+                }
+            });
+            self._adjust(callback);
+        }
+    },
+
+    _joinAll: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        o.itemsCreator({
+            type: BI.MultiSelectCombo.REQ_GET_ALL_DATA,
+            keywords: [this.trigger.getKey()]
+        }, function (ob) {
+            var items = BI.pluck(ob.items, "value");
+            if (self.storeValue.type === res.type) {
+                var change = false;
+                var map = self._makeMap(self.storeValue.value);
+                BI.each(items, function (i, v) {
+                    if (BI.isNotNull(map[v])) {
+                        change = true;
+                        delete map[v];
+                    }
+                });
+                change && (self.storeValue.value = BI.values(map));
+                self._adjust(callback);
+                return;
+            }
+            var selectedMap = self._makeMap(self.storeValue.value);
+            var notSelectedMap = self._makeMap(res.value);
+            var newItems = [];
+            BI.each(items, function (i, item) {
+                if (BI.isNotNull(selectedMap[items[i]])) {
+                    delete selectedMap[items[i]];
+                }
+                if (BI.isNull(notSelectedMap[items[i]])) {
+                    newItems.push(item);
+                }
+            });
+            self.storeValue.value = newItems.concat(BI.values(selectedMap));
+            self._adjust(callback);
+        })
+    },
+
+    _adjust: function (callback) {
+        var self = this, o = this.options;
+        if (!this._count) {
+            o.itemsCreator({
+                type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                self._count = res.count;
+                adjust();
+                callback();
+            });
+        } else {
+            adjust();
+            callback();
+        }
+        function adjust() {
+            if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.Multi,
+                    value: []
+                }
+            } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.All,
+                    value: []
+                }
+            }
+        }
+    },
+
+    _join: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        this._assertValue(this.storeValue);
+        if (this.storeValue.type === res.type) {
+            var map = this._makeMap(this.storeValue.value);
+            BI.each(res.value, function (i, v) {
+                if (!map[v]) {
+                    self.storeValue.value.push(v);
+                    map[v] = v;
+                }
+            });
+            var change = false;
+            BI.each(res.assist, function (i, v) {
+                if (BI.isNotNull(map[v])) {
+                    change = true;
+                    delete map[v];
+                }
+            });
+            change && (this.storeValue.value = BI.values(map));
+            self._adjust(callback);
+            return;
+        }
+        this._joinAll(res, callback);
+    },
+
+    _setStartValue: function (value) {
+        this._startValue = value;
+        this.popup.setStartValue(value);
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.combo.setValue(this.storeValue);
+        this.trigger.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.storeValue;
+    },
+
+    populate: function () {
+        this._count = null;
+        this.combo.populate.apply(this.combo, arguments);
+    }
+});
+
+BI.extend(BI.MultiSelectCombo, {
+    REQ_GET_DATA_LENGTH: 0,
+    REQ_GET_ALL_DATA: -1
+});
+
+BI.MultiSelectCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+
+$.shortcut('bi.multi_select_combo', BI.MultiSelectCombo);
\ No newline at end of file
diff --git a/src/widget/multiselect/multiselect.loader.js b/src/widget/multiselect/multiselect.loader.js
new file mode 100644
index 000000000..92abcd946
--- /dev/null
+++ b/src/widget/multiselect/multiselect.loader.js
@@ -0,0 +1,172 @@
+/**
+ * 多选加载数据面板
+ * Created by guy on 15/11/2.
+ * @class BI.MultiSelectLoader
+ * @extends Widget
+ */
+BI.MultiSelectLoader = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-loader',
+            logic: {
+                dynamic: true
+            },
+            el: {
+                height: 400
+            },
+            valueFormatter: BI.emptyFn,
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectLoader.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+        var hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            logic: opts.logic,
+            el: BI.extend({
+                onLoaded: opts.onLoaded,
+                el: {
+                    type: "bi.loader",
+                    isDefaultInit: false,
+                    logic: {
+                        dynamic: true,
+                        scrolly: true
+                    },
+                    el: {
+                        chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                        behaviors: {
+                            redmark: function () {
+                                return true;
+                            }
+                        },
+                        layouts: [{
+                            type: "bi.vertical"
+                        }]
+                    }
+                }
+            }, opts.el),
+            itemsCreator: function (op, callback) {
+                var startValue = self._startValue;
+                self.storeValue && (op = BI.extend(op || {}, {
+                    selected_values: BI.isKey(startValue) && self.storeValue.type === BI.Selection.Multi
+                        ? self.storeValue.value.concat(startValue) : self.storeValue.value
+                }));
+                opts.itemsCreator(op, function (ob) {
+                    hasNext = ob.hasNext;
+                    var firstItems = [];
+                    if (op.times === 1 && self.storeValue) {
+                        var json = BI.map(self.storeValue.value, function (i, v) {
+                            var txt = opts.valueFormatter(v) || v;
+                            return {
+                                text: txt,
+                                value: v,
+                                title: txt,
+                                selected: self.storeValue.type === BI.Selection.Multi
+                            }
+                        });
+                        if (BI.isKey(self._startValue) && !self.storeValue.value.contains(self._startValue)) {
+                            var txt = opts.valueFormatter(startValue) || startValue;
+                            json.unshift({
+                                text: txt,
+                                value: startValue,
+                                title: txt,
+                                selected: true
+                            })
+                        }
+                        firstItems = self._createItems(json);
+                    }
+                    callback(firstItems.concat(self._createItems(ob.items)), ob.keyword || "");
+                    if (op.times === 1 && self.storeValue) {
+                        BI.isKey(startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](startValue);
+                        self.setValue(self.storeValue);
+                    }
+                    (op.times === 1) && self._scrollToTop();
+                });
+            },
+            hasNext: function () {
+                return hasNext;
+            }
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.SelectList.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectLoader.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            logic: this.options.logic,
+            height: 25,
+            selected: this.isAllSelected()
+        })
+    },
+
+    _scrollToTop: function () {
+        var self = this;
+        BI.delay(function () {
+            self.button_group.element.scrollTop(0);
+        }, 30);
+    },
+
+    isAllSelected: function () {
+        return this.button_group.isAllSelected();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    setStartValue: function (v) {
+        this._startValue = v;
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.button_group.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.button_group.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.button_group.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.button_group.resetWidth(w);
+    }
+});
+
+BI.MultiSelectLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_loader', BI.MultiSelectLoader);
\ No newline at end of file
diff --git a/src/widget/multiselect/multiselect.popup.view.js b/src/widget/multiselect/multiselect.popup.view.js
new file mode 100644
index 000000000..e638e79c4
--- /dev/null
+++ b/src/widget/multiselect/multiselect.popup.view.js
@@ -0,0 +1,95 @@
+/**
+ * 带加载的多选下拉面板
+ * @class BI.MultiSelectPopupView
+ * @extends Widget
+ */
+BI.MultiSelectPopupView = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-popup-view',
+            maxWidth: 'auto',
+            minWidth: 135,
+            maxHeight: 400,
+            valueFormatter: BI.emptyFn,
+            itemsCreator: BI.emptyFn,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectPopupView.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+
+        this.loader = BI.createWidget({
+            type: "bi.multi_select_loader",
+            itemsCreator: opts.itemsCreator,
+            valueFormatter: opts.valueFormatter,
+            onLoaded: opts.onLoaded
+        });
+
+        this.popupView = BI.createWidget({
+            type: "bi.multi_popup_view",
+            stopPropagation: false,
+            maxWidth: opts.maxWidth,
+            minWidth: opts.minWidth,
+            maxHeight: opts.maxHeight,
+            element: this,
+            buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')],
+            el: this.loader
+        });
+
+        this.popupView.on(BI.MultiPopupView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectPopupView.EVENT_CHANGE);
+        });
+        this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CLEAR);
+                    break;
+                case 1:
+                    self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM);
+                    break;
+            }
+        });
+    },
+
+    isAllSelected: function () {
+        return this.loader.isAllSelected();
+    },
+
+    setStartValue: function (v) {
+        this.loader.setStartValue(v);
+    },
+
+    setValue: function (v) {
+        this.popupView.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popupView.getValue();
+    },
+
+    populate: function (items) {
+        this.popupView.populate.apply(this.popupView, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.popupView.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.popupView.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.popupView.resetWidth(w);
+    }
+});
+
+BI.MultiSelectPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiSelectPopupView.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+
+
+$.shortcut('bi.multi_select_popup_view', BI.MultiSelectPopupView);
\ No newline at end of file
diff --git a/src/widget/multiselect/multiselect.trigger.js b/src/widget/multiselect/multiselect.trigger.js
new file mode 100644
index 000000000..50cd4cb19
--- /dev/null
+++ b/src/widget/multiselect/multiselect.trigger.js
@@ -0,0 +1,153 @@
+/**
+ *
+ * 复选下拉框
+ * @class BI.MultiSelectTrigger
+ * @extends BI.Trigger
+ */
+
+BI.MultiSelectTrigger = BI.inherit(BI.Trigger, {
+
+    constants: {
+        height: 14,
+        rgap: 4,
+        lgap: 4
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-trigger",
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            searcher: {},
+            switcher: {},
+
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectTrigger.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+        if (o.height) {
+            this.setHeight(o.height - 2);
+        }
+
+        this.searcher = BI.createWidget(o.searcher, {
+            type: "bi.multi_select_searcher",
+            height: o.height,
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            popup: {},
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_START);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_PAUSE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_SEARCHING, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_SEARCHING, arguments);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_STOP);
+        });
+        this.searcher.on(BI.MultiSelectSearcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_CHANGE, arguments);
+        });
+        this.numberCounter = BI.createWidget(o.switcher, {
+            type: 'bi.multi_select_check_selected_switcher',
+            valueFormatter: o.valueFormatter,
+            itemsCreator: o.itemsCreator,
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK);
+        });
+        this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW);
+        });
+
+        var wrapNumberCounter = BI.createWidget({
+            type: 'bi.right_vertical_adapt',
+            hgap: 4,
+            items: [{
+                el: this.numberCounter
+            }]
+        });
+
+        var wrapper = BI.createWidget({
+            type: 'bi.htape',
+            element: this,
+            items: [
+                {
+                    el: this.searcher,
+                    width: 'fill'
+                }, {
+                    el: wrapNumberCounter,
+                    width: 0
+                }, {
+                    el: BI.createWidget(),
+                    width: 30
+                }]
+        });
+
+        this.numberCounter.on(BI.Events.VIEW, function (b) {
+            BI.nextTick(function () {//自动调整宽度
+                wrapper.attr("items")[1].width = (b === true ? self.numberCounter.element.outerWidth() + 8 : 0);
+                wrapper.resize();
+            });
+        });
+
+        this.element.click(function (e) {
+            if (self.element.__isMouseInBounds__(e) && !self.numberCounter.element.__isMouseInBounds__(e)) {
+                self.numberCounter.hideView();
+            }
+        });
+    },
+
+    getCounter: function () {
+        return this.numberCounter;
+    },
+
+    getSearcher: function () {
+        return this.searcher;
+    },
+
+    stopEditing: function () {
+        this.searcher.stopSearch();
+        this.numberCounter.hideView();
+    },
+
+    setValue: function (ob) {
+        this.searcher.setValue(ob);
+        this.numberCounter.setValue(ob);
+    },
+
+    setEnable: function (v) {
+        this.searcher.setEnable(v);
+    },
+
+    getKey: function () {
+        return this.searcher.getKey();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    }
+});
+
+BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK";
+BI.MultiSelectTrigger.EVENT_COUNTER_CLICK = "EVENT_COUNTER_CLICK";
+BI.MultiSelectTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectTrigger.EVENT_START = "EVENT_START";
+BI.MultiSelectTrigger.EVENT_STOP = "EVENT_STOP";
+BI.MultiSelectTrigger.EVENT_PAUSE = "EVENT_PAUSE";
+BI.MultiSelectTrigger.EVENT_SEARCHING = "EVENT_SEARCHING";
+BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW = "EVENT_BEFORE_COUNTER_POPUPVIEW";
+
+$.shortcut('bi.multi_select_trigger', BI.MultiSelectTrigger);
\ No newline at end of file
diff --git a/src/widget/multiselect/search/multiselect.search.loader.js b/src/widget/multiselect/search/multiselect.search.loader.js
new file mode 100644
index 000000000..b4ba119a5
--- /dev/null
+++ b/src/widget/multiselect/search/multiselect.search.loader.js
@@ -0,0 +1,156 @@
+/**
+ * 多选加载数据搜索loader面板
+ * Created by guy on 15/11/4.
+ * @class BI.MultiSelectSearchLoader
+ * @extends Widget
+ */
+BI.MultiSelectSearchLoader = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearchLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-search-loader',
+            itemsCreator: BI.emptyFn,
+            keywordGetter: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearchLoader.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+        var hasNext = false;
+
+        this.button_group = BI.createWidget({
+            type: "bi.select_list",
+            element: this,
+            logic: {
+                dynamic: false
+            },
+            el: {
+                tipText: BI.i18nText("BI-No_Select"),
+                el: {
+                    type: "bi.loader",
+                    isDefaultInit: false,
+                    logic: {
+                        dynamic: true,
+                        scrolly: true
+                    },
+                    el: {
+                        chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+                        behaviors: {
+                            redmark: function () {
+                                return true;
+                            }
+                        },
+                        layouts: [{
+                            type: "bi.vertical"
+                        }]
+                    }
+                }
+            },
+            itemsCreator: function (op, callback) {
+                self.storeValue && (op = BI.extend(op || {}, {
+                    selected_values: self.storeValue.value
+                }));
+                opts.itemsCreator(op, function (ob) {
+                    var keyword = ob.keyword = opts.keywordGetter();
+                    hasNext = ob.hasNext;
+                    var firstItems = [];
+                    if (op.times === 1 && self.storeValue) {
+                        var json = self._filterValues(self.storeValue);
+                        firstItems = self._createItems(json);
+                    }
+                    callback(firstItems.concat(self._createItems(ob.items)), keyword);
+                    if (op.times === 1 && self.storeValue) {
+                        self.setValue(self.storeValue);
+                    }
+                });
+            },
+            hasNext: function () {
+                return hasNext;
+            }
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.SelectList.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectSearchLoader.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _createItems: function (items) {
+        return BI.createItems(items, {
+            type: "bi.multi_select_item",
+            logic: {
+                dynamic: false
+            },
+            height: 25,
+            selected: this.isAllSelected()
+        })
+    },
+
+    isAllSelected: function () {
+        return this.button_group.isAllSelected();
+    },
+
+    _filterValues: function (src) {
+        var o = this.options;
+        var keyword = o.keywordGetter();
+        var values = BI.deepClone(src.value) || [];
+        var newValues = BI.map(values, function (i, v) {
+            return {
+                text: o.valueFormatter(v) || v,
+                value: v
+            };
+        });
+        if (BI.isKey(keyword)) {
+            var search = BI.Func.getSearchResult(newValues, keyword);
+            values = search.matched.concat(search.finded);
+        }
+        return BI.map(values, function (i, v) {
+            return {
+                text: v.text,
+                title: v.text,
+                value: v.value,
+                selected: src.type === BI.Selection.All
+            }
+        })
+    },
+
+    setValue: function (v) {
+        this.storeValue = v;
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue();
+    },
+
+    getAllButtons: function () {
+        return this.button_group.getAllButtons();
+    },
+
+    empty: function () {
+        this.button_group.empty();
+    },
+
+    populate: function (items) {
+        this.button_group.populate.apply(this.button_group, arguments);
+    },
+
+    setEnable: function (arg) {
+        this.button_group.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.button_group.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.button_group.resetWidth(w);
+    }
+});
+
+BI.MultiSelectSearchLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_search_loader', BI.MultiSelectSearchLoader);
\ No newline at end of file
diff --git a/src/widget/multiselect/search/multiselect.search.pane.js b/src/widget/multiselect/search/multiselect.search.pane.js
new file mode 100644
index 000000000..a85ffff2c
--- /dev/null
+++ b/src/widget/multiselect/search/multiselect.search.pane.js
@@ -0,0 +1,102 @@
+/**
+ *
+ * 在搜索框中输入文本弹出的面板
+ * @class BI.MultiSelectSearchPane
+ * @extends Widget
+ */
+
+BI.MultiSelectSearchPane = BI.inherit(BI.Widget, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearchPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-select-search-pane",
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            keywordGetter: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearchPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.tooltipClick = BI.createWidget({
+            type: "bi.label",
+            invisible: true,
+            text: BI.i18nText('BI-Click_Blank_To_Select'),
+            cls: 'multi-select-toolbar',
+            height: this.constants.height
+        });
+
+        this.loader = BI.createWidget({
+            type: "bi.multi_select_search_loader",
+            keywordGetter: o.keywordGetter,
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator.apply(self, [op, function (res) {
+                    callback(res);
+                    self.setKeyword(o.keywordGetter());
+                }]);
+            }
+        });
+        this.loader.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.resizer = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.tooltipClick,
+                height: 0
+            }, {
+                el: this.loader
+            }]
+        });
+        this.tooltipClick.setVisible(false);
+    },
+
+    setKeyword: function (keyword) {
+        var btn;
+        var isVisible = this.loader.getAllButtons().length > 0 && (btn = this.loader.getAllButtons()[0]) && (keyword === btn.getValue());
+        if (isVisible !== this.tooltipClick.isVisible()) {
+            this.tooltipClick.setVisible(isVisible);
+            this.resizer.attr("items")[0].height = (isVisible ? this.constants.height : 0);
+            this.resizer.resize();
+        }
+    },
+
+    isAllSelected: function () {
+        return this.loader.isAllSelected();
+    },
+
+    hasMatched: function () {
+        return this.tooltipClick.isVisible();
+    },
+
+    setValue: function (v) {
+        this.loader.setValue(v);
+    },
+
+    getValue: function () {
+        return this.loader.getValue();
+    },
+
+    empty: function () {
+        this.loader.empty();
+    },
+
+    populate: function (items) {
+        this.loader.populate.apply(this.loader, arguments);
+    }
+});
+
+BI.MultiSelectSearchPane.EVENT_CHANGE = "EVENT_CHANGE";
+
+$.shortcut("bi.multi_select_search_pane", BI.MultiSelectSearchPane);
\ No newline at end of file
diff --git a/src/widget/multiselect/trigger/button.checkselected.js b/src/widget/multiselect/trigger/button.checkselected.js
new file mode 100644
index 000000000..3e64bf163
--- /dev/null
+++ b/src/widget/multiselect/trigger/button.checkselected.js
@@ -0,0 +1,77 @@
+/**
+ * 查看已选按钮
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectCheckSelectedButton
+ * @extends BI.Single
+ */
+BI.MultiSelectCheckSelectedButton = BI.inherit(BI.Single, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-check-selected-button',
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckSelectedButton.superclass._init.apply(this, arguments);
+        var self = this;
+        this.numberCounter = BI.createWidget({
+            type: 'bi.text_button',
+            element: this,
+            hgap: 4,
+            text: "0",
+            textAlign: 'center',
+            textHeight: 15
+        });
+        this.numberCounter.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.numberCounter.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments);
+        });
+
+        this.numberCounter.element.hover(function () {
+            self.numberCounter.setTag(self.numberCounter.getText());
+            self.numberCounter.setText(self._const.checkSelected);
+        }, function () {
+            self.numberCounter.setText(self.numberCounter.getTag());
+        });
+        this.setVisible(false);
+    },
+
+    setValue: function (ob) {
+        var self = this, o = this.options;
+        ob || (ob = {});
+        ob.type || (ob.type = BI.Selection.Multi);
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            o.itemsCreator({
+                type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                var length = res.count - ob.value.length;
+                BI.nextTick(function(){
+                    self.numberCounter.setText(length);
+                    self.setVisible(length > 0);
+                });
+            });
+            return;
+        }
+        BI.nextTick(function(){
+            self.numberCounter.setText(ob.value.length);
+            self.setVisible(ob.value.length > 0);
+        })
+    },
+
+    getValue: function () {
+
+    }
+});
+
+BI.MultiSelectCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_select_check_selected_button', BI.MultiSelectCheckSelectedButton);
\ No newline at end of file
diff --git a/src/widget/multiselect/trigger/editor.multiselect.js b/src/widget/multiselect/trigger/editor.multiselect.js
new file mode 100644
index 000000000..b83e435df
--- /dev/null
+++ b/src/widget/multiselect/trigger/editor.multiselect.js
@@ -0,0 +1,86 @@
+/**
+ * 多选输入框
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectEditor
+ * @extends Widget
+ */
+BI.MultiSelectEditor = BI.inherit(BI.Widget, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectEditor.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-editor',
+            el: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectEditor.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget(o.el, {
+            type: 'bi.state_editor',
+            element: this,
+            height: o.height,
+            watermark: BI.i18nText('BI-Basic_Search'),
+            allowBlank: true
+        });
+
+        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.editor.on(BI.StateEditor.EVENT_PAUSE, function () {
+            self.fireEvent(BI.MultiSelectEditor.EVENT_PAUSE);
+        });
+        this.editor.on(BI.StateEditor.EVENT_CLICK_LABEL, function () {
+
+        });
+    },
+
+    focus: function () {
+        this.editor.focus();
+    },
+
+    blur: function () {
+        this.editor.blur();
+    },
+
+    setState: function (state) {
+        this.editor.setState(state);
+    },
+
+    setValue: function (v) {
+        this.editor.setValue(v);
+    },
+
+    setEnable: function(v){
+        this.editor.setEnable(v);
+    },
+
+    getValue: function () {
+        var v = this.editor.getState();
+        if (BI.isArray(v) && v.length > 0) {
+            return v[v.length - 1];
+        } else {
+            return "";
+        }
+    },
+
+    getKeywords: function () {
+        var val = this.editor.getLastValidValue();
+        var keywords = val.match(/[\S]+/g);
+        if (BI.isEndWithBlank(val)) {
+            return keywords.concat([' ']);
+        }
+        return keywords;
+    },
+
+    populate: function (items) {
+
+    }
+});
+BI.MultiSelectEditor.EVENT_PAUSE = "MultiSelectEditor.EVENT_PAUSE";
+$.shortcut('bi.multi_select_editor', BI.MultiSelectEditor);
\ No newline at end of file
diff --git a/src/widget/multiselect/trigger/searcher.multiselect.js b/src/widget/multiselect/trigger/searcher.multiselect.js
new file mode 100644
index 000000000..046855208
--- /dev/null
+++ b/src/widget/multiselect/trigger/searcher.multiselect.js
@@ -0,0 +1,143 @@
+/**
+ * searcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectSearcher
+ * @extends Widget
+ */
+BI.MultiSelectSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-searcher',
+            itemsCreator: BI.emptyFn,
+            el: {},
+            popup: {},
+            valueFormatter: BI.emptyFn,
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget(o.el, {
+            type: 'bi.multi_select_editor',
+            height: o.height
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            element: this,
+            height: o.height,
+            isAutoSearch: false,
+            isAutoSync: false,
+            onSearch: function (op, callback) {
+                callback();
+            },
+            el: this.editor,
+
+            popup: BI.extend({
+                type: "bi.multi_select_search_pane",
+                valueFormatter: o.valueFormatter,
+                keywordGetter: function () {
+                    return self.editor.getValue();
+                },
+                itemsCreator: function (op, callback) {
+                    op.keyword = self.editor.getValue();
+                    this.setKeyword(op.keyword);
+                    o.itemsCreator(op, callback);
+                }
+            }, o.popup),
+
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.Searcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_START);
+        });
+        this.searcher.on(BI.Searcher.EVENT_PAUSE, function () {
+            if (this.hasMatched()) {
+
+            }
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.Searcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_STOP);
+        });
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_CHANGE, arguments);
+        });
+        this.searcher.on(BI.Searcher.EVENT_SEARCHING, function () {
+            var keywords = this.getKeywords();
+            self.fireEvent(BI.MultiSelectSearcher.EVENT_SEARCHING, keywords);
+        });
+    },
+
+    adjustView: function () {
+        this.searcher.adjustView();
+    },
+
+    isSearching: function () {
+        return this.searcher.isSearching();
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    getKeyword: function () {
+        return this.editor.getValue();
+    },
+
+    hasMatched: function () {
+        return this.searcher.hasMatched();
+    },
+
+    hasChecked: function () {
+        return this.searcher.getView() && this.searcher.getView().hasChecked();
+    },
+
+    setState: function (ob) {
+        ob || (ob = {});
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All);
+        } else {
+            if (BI.size(ob.value) === 1) {
+                this.editor.setState(ob.value[0] + "");
+            } else {
+                this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None);
+            }
+        }
+    },
+
+    setValue: function (ob) {
+        this.setState(ob);
+        this.searcher.setValue(ob);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    setEnable: function (v) {
+        this.editor.setEnable(v);
+    },
+
+    populate: function (items) {
+        this.searcher.populate.apply(this.searcher, arguments);
+    }
+});
+
+BI.MultiSelectSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.MultiSelectSearcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiSelectSearcher.EVENT_START = "EVENT_START";
+BI.MultiSelectSearcher.EVENT_STOP = "EVENT_STOP";
+BI.MultiSelectSearcher.EVENT_PAUSE = "EVENT_PAUSE";
+BI.MultiSelectSearcher.EVENT_SEARCHING = "EVENT_SEARCHING";
+$.shortcut('bi.multi_select_searcher', BI.MultiSelectSearcher);
\ No newline at end of file
diff --git a/src/widget/multiselect/trigger/switcher.checkselected.js b/src/widget/multiselect/trigger/switcher.checkselected.js
new file mode 100644
index 000000000..d5f13a4be
--- /dev/null
+++ b/src/widget/multiselect/trigger/switcher.checkselected.js
@@ -0,0 +1,94 @@
+/**
+ * 查看已选switcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiSelectCheckSelectedSwitcher
+ * @extends Widget
+ */
+BI.MultiSelectCheckSelectedSwitcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiSelectCheckSelectedSwitcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-select-check-selected-switcher',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            el: {},
+            popup: {},
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiSelectCheckSelectedSwitcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget(o.el, {
+            type: "bi.multi_select_check_selected_button",
+            itemsCreator: o.itemsCreator
+        });
+        this.button.on(BI.Events.VIEW, function () {
+            self.fireEvent(BI.Events.VIEW, arguments);
+        });
+        this.switcher = BI.createWidget({
+            type: "bi.switcher",
+            toggle: false,
+            element: this,
+            el: this.button,
+            popup: BI.extend({
+                type: "bi.multi_select_check_pane",
+                valueFormatter: o.valueFormatter,
+                itemsCreator: o.itemsCreator,
+                onClickContinueSelect: function () {
+                    self.switcher.hideView();
+                }
+            }, o.popup),
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.switcher.on(BI.Switcher.EVENT_TRIGGER_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE);
+        });
+        this.switcher.on(BI.Switcher.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW);
+        });
+        this.switcher.on(BI.Switcher.EVENT_AFTER_POPUPVIEW, function () {
+            var me = this;
+            BI.nextTick(function () {
+                me.populate();
+            });
+        });
+
+        this.switcher.element.click(function (e) {
+            e.stopPropagation();
+        });
+    },
+
+    adjustView: function () {
+        this.switcher.adjustView();
+    },
+
+    hideView: function () {
+        this.switcher.empty();
+        this.switcher.hideView();
+    },
+
+    setValue: function (v) {
+        this.switcher.setValue(v);
+    },
+
+    setButtonChecked: function (v) {
+        this.button.setValue(v)
+    },
+
+    getValue: function () {
+
+    },
+
+    populate: function (items) {
+        this.switcher.populate.apply(this.switcher, arguments);
+    }
+});
+
+BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE = "MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE";
+BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW = "MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW";
+$.shortcut('bi.multi_select_check_selected_switcher', BI.MultiSelectCheckSelectedSwitcher);
\ No newline at end of file
diff --git a/src/widget/multistringlist/multistringlist.js b/src/widget/multistringlist/multistringlist.js
new file mode 100644
index 000000000..06366f0bf
--- /dev/null
+++ b/src/widget/multistringlist/multistringlist.js
@@ -0,0 +1,320 @@
+/**
+ * Created by zcf on 2016/12/14.
+ */
+BI.MultiStringList = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiStringList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-string-list',
+            itemsCreator: BI.emptyFn,
+            valueFormatter: BI.emptyFn,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.MultiStringList.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        var assertShowValue = function () {
+            BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue);
+            self.trigger.getSearcher().setState(self.storeValue);
+            self.trigger.getCounter().setButtonChecked(self.storeValue);
+        };
+        this.storeValue = {};
+
+
+        this.popup = BI.createWidget({
+            type: "bi.multi_select_loader",
+            cls: "popup-multi-string-list",
+            itemsCreator: o.itemsCreator,
+            valueFormatter: o.valueFormatter,
+            onLoaded: o.onLoaded,
+            el: {
+                height: ""
+            }
+        });
+        this.popup.on(BI.MultiSelectLoader.EVENT_CHANGE, function () {
+            self.storeValue = this.getValue();
+            self._adjust(function () {
+                assertShowValue();
+                self.fireEvent(BI.MultiStringList.EVENT_CHANGE);
+            });
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: {
+                    left: 1,
+                    top: 0,
+                    right: 2,
+                    bottom: 1
+                }
+            },
+            valueFormatter: o.valueFormatter,
+            itemsCreator: function (op, callback) {
+                o.itemsCreator(op, function (res) {
+                    if (op.times === 1 && BI.isNotNull(op.keyword)) {
+                        self.trigger.setValue(self.getValue());
+                    }
+                    callback.apply(self, arguments);
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self._setStartValue("");
+            this.getSearcher().setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self._setStartValue("");
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_PAUSE, function () {
+            if (this.getSearcher().hasMatched()) {
+                var keyword = this.getSearcher().getKeyword();
+                self._join({
+                    type: BI.Selection.Multi,
+                    value: [keyword]
+                }, function () {
+                    self.trigger.setValue(self.storeValue);
+                    self.popup.setValue(self.storeValue);
+                    self._setStartValue(keyword);
+                    assertShowValue();
+                    self.populate();
+                    self._setStartValue("");
+                    self.fireEvent(BI.MultiStringList.EVENT_CHANGE);
+                })
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_SEARCHING, function (keywords) {
+            var last = BI.last(keywords);
+            keywords = BI.initial(keywords || []);
+            if (keywords.length > 0) {
+                self._joinKeywords(keywords, function () {
+                    if (BI.isEndWithBlank(last)) {
+                        self.trigger.setValue(self.storeValue);
+                        self.popup.setValue(self.storeValue);
+                        assertShowValue();
+                        self.popup.populate();
+                        self._setStartValue("");
+                    } else {
+                        self.trigger.setValue(self.storeValue);
+                        self.popup.setValue(self.storeValue);
+                        assertShowValue();
+                    }
+                });
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function (value, obj) {
+            if (obj instanceof BI.MultiSelectBar) {
+                self._joinAll(this.getValue(), function () {
+                    assertShowValue();
+                });
+            } else {
+                self._join(this.getValue(), function () {//安徽省 北京
+                    assertShowValue();
+                });
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            this.getCounter().setValue(self.storeValue);
+        });
+        var div = BI.createWidget({
+            type: "bi.layout"
+        });
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            height: "100%",
+            width: "100%",
+            items: [{
+                el: this.trigger,
+                height: 25
+            }, {
+                el: div,
+                height: 2
+            }, {
+                el: this.popup,
+                height: "fill"
+            }]
+        });
+    },
+    _defaultState: function () {
+        this.trigger.stopEditing();
+    },
+
+    _assertValue: function (val) {
+        val || (val = {});
+        val.type || (val.type = BI.Selection.Multi);
+        val.value || (val.value = []);
+    },
+
+    _makeMap: function (values) {
+        return BI.makeObject(values || []);
+    },
+
+    _joinKeywords: function (keywords, callback) {
+        var self = this, o = this.options;
+        this._assertValue(this.storeValue);
+        if (!this._allData) {
+            o.itemsCreator({
+                type: BI.MultiStringList.REQ_GET_ALL_DATA
+            }, function (ob) {
+                self._allData = BI.pluck(ob.items, "value");
+                digest(self._allData);
+            })
+        } else {
+            digest(this._allData)
+        }
+
+        function digest(items) {
+            var selectedMap = self._makeMap(items);
+            BI.each(keywords, function (i, val) {
+                if (BI.isNotNull(selectedMap[val])) {
+                    self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val);
+                }
+            });
+            self._adjust(callback);
+        }
+    },
+
+    _joinAll: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        o.itemsCreator({
+            type: BI.MultiStringList.REQ_GET_ALL_DATA,
+            keyword: this.trigger.getKey()
+        }, function (ob) {
+            var items = BI.pluck(ob.items, "value");
+            if (self.storeValue.type === res.type) {
+                var change = false;
+                var map = self._makeMap(self.storeValue.value);
+                BI.each(items, function (i, v) {
+                    if (BI.isNotNull(map[v])) {
+                        change = true;
+                        delete map[v];
+                    }
+                });
+                change && (self.storeValue.value = BI.values(map));
+                self._adjust(callback);
+                return;
+            }
+            var selectedMap = self._makeMap(self.storeValue.value);
+            var notSelectedMap = self._makeMap(res.value);
+            var newItems = [];
+            BI.each(items, function (i, item) {
+                if (BI.isNotNull(selectedMap[items[i]])) {
+                    delete selectedMap[items[i]];
+                }
+                if (BI.isNull(notSelectedMap[items[i]])) {
+                    newItems.push(item);
+                }
+            });
+            self.storeValue.value = newItems.concat(BI.values(selectedMap));
+            self._adjust(callback);
+        })
+    },
+
+    _adjust: function (callback) {
+        var self = this, o = this.options;
+        if (!this._count) {
+            o.itemsCreator({
+                type: BI.MultiStringList.REQ_GET_DATA_LENGTH
+            }, function (res) {
+                self._count = res.count;
+                adjust();
+                callback();
+            });
+        } else {
+            adjust();
+            callback();
+        }
+        function adjust() {
+            if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.Multi,
+                    value: []
+                }
+            } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) {
+                self.storeValue = {
+                    type: BI.Selection.All,
+                    value: []
+                }
+            }
+        }
+    },
+
+    _join: function (res, callback) {
+        var self = this, o = this.options;
+        this._assertValue(res);
+        this._assertValue(this.storeValue);
+        if (this.storeValue.type === res.type) {
+            var map = this._makeMap(this.storeValue.value);
+            BI.each(res.value, function (i, v) {
+                if (!map[v]) {
+                    self.storeValue.value.push(v);
+                    map[v] = v;
+                }
+            });
+            var change = false;
+            BI.each(res.assist, function (i, v) {
+                if (BI.isNotNull(map[v])) {
+                    change = true;
+                    delete map[v];
+                }
+            });
+            change && (this.storeValue.value = BI.values(map));
+            self._adjust(callback);
+            return;
+        }
+        this._joinAll(res, callback);
+    },
+
+    _setStartValue: function (value) {
+        this._startValue = value;
+        this.popup.setStartValue(value);
+    },
+
+    // isAllSelected: function () {
+    //     return this.popup.isAllSelected();
+    // },
+
+    resize: function () {
+        this.trigger.getCounter().adjustView();
+        this.trigger.getSearcher().adjustView();
+    },
+
+    setEnable: function (v) {
+        this.trigger.setEnable(v);
+        this.popup.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue = v || {};
+        this._assertValue(this.storeValue);
+        this.popup.setValue(this.storeValue);
+        this.trigger.setValue(this.storeValue);
+    },
+
+    getValue: function () {
+        return this.storeValue;
+    },
+
+    populate: function () {
+        this._count = null;
+        this._allData = null;
+        this.popup.populate.apply(this.popup, arguments);
+        this.trigger.populate.apply(this.trigger, arguments);
+    }
+});
+
+BI.extend(BI.MultiStringList, {
+    REQ_GET_DATA_LENGTH: 0,
+    REQ_GET_ALL_DATA: -1
+});
+
+BI.MultiStringList.EVENT_CHANGE = "BI.MultiStringList.EVENT_CHANGE";
+$.shortcut("bi.multi_string_list", BI.MultiStringList);
\ No newline at end of file
diff --git a/src/widget/multitree/check/multi.tree.check.pane.js b/src/widget/multitree/check/multi.tree.check.pane.js
new file mode 100644
index 000000000..81dd55ace
--- /dev/null
+++ b/src/widget/multitree/check/multi.tree.check.pane.js
@@ -0,0 +1,115 @@
+/**
+ *
+ * @class BI.MultiTreeCheckPane
+ * @extends BI.Pane
+ */
+BI.MultiTreeCheckPane = BI.inherit(BI.Pane, {
+
+    constants: {
+        height: 25,
+        lgap: 10,
+        tgap: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-tree-check-pane",
+            onClickContinueSelect: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCheckPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.selected_values = {};
+
+        var continueSelect = BI.createWidget({
+            type: 'bi.text_button',
+            text: BI.i18nText('BI-Continue_Select'),
+            cls: 'multi-tree-check-selected'
+        });
+        continueSelect.on(BI.TextButton.EVENT_CHANGE, function () {
+            opts.onClickContinueSelect();
+            BI.nextTick(function () {
+                self.empty();
+            });
+        });
+
+        var backToPopup = BI.createWidget({
+            type: 'bi.left',
+            cls: 'multi-tree-continue-select',
+            items: [
+                {
+                    el: {
+                        type: "bi.label",
+                        text: BI.i18nText('BI-Selected_Data')
+                    },
+                    lgap: this.constants.lgap,
+                    tgap: this.constants.tgap
+                },
+                {
+                    el: continueSelect,
+                    lgap: this.constants.lgap,
+                    tgap: this.constants.tgap
+                }]
+        });
+
+        this.display = BI.createWidget({
+            type: "bi.display_tree",
+            cls: "bi-multi-tree-display",
+            itemsCreator: function (op, callback) {
+                op.type = BI.TreeView.REQ_TYPE_SELECTED_DATA;
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.display.on(BI.Events.AFTERINIT, function () {
+            self.fireEvent(BI.Events.AFTERINIT);
+        });
+
+        this.display.on(BI.TreeView.EVENT_INIT, function () {
+            backToPopup.setVisible(false);
+        });
+
+        this.display.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            backToPopup.setVisible(true);
+        });
+
+        BI.createWidget({
+            type: 'bi.vtape',
+            element: this,
+            items: [{
+                height: this.constants.height,
+                el: backToPopup
+            }, {
+                height: 'fill',
+                el: this.display
+            }]
+        });
+
+    },
+
+    empty: function () {
+        this.display.empty();
+    },
+
+    populate: function (configs) {
+        this.display.stroke(configs);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.display.setValue(v.value);
+    },
+
+    getValue: function () {
+
+    }
+});
+
+BI.MultiTreeCheckPane.EVENT_CONTINUE_CLICK = "EVENT_CONTINUE_CLICK";
+
+
+$.shortcut("bi.multi_tree_check_pane", BI.MultiTreeCheckPane);
\ No newline at end of file
diff --git a/src/widget/multitree/multi.tree.combo.js b/src/widget/multitree/multi.tree.combo.js
new file mode 100644
index 000000000..3da7e4103
--- /dev/null
+++ b/src/widget/multitree/multi.tree.combo.js
@@ -0,0 +1,252 @@
+/**
+ *
+ * @class BI.MultiTreeCombo
+ * @extends BI.Single
+ */
+
+BI.MultiTreeCombo = BI.inherit(BI.Single, {
+
+    constants: {
+        offset: {
+            top: 1,
+            left: 1,
+            right: 2,
+            bottom: 33
+        }
+    },
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-combo',
+            itemsCreator: BI.emptyFn,
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCombo.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.popup = BI.createWidget({
+            type: 'bi.multi_tree_popup_view',
+            itemsCreator: o.itemsCreator,
+            onLoaded: function () {
+                BI.nextTick(function () {
+                    self.trigger.getCounter().adjustView();
+                    self.trigger.getSearcher().adjustView();
+                });
+            }
+        });
+        var isInit = false;
+        var want2showCounter = false;
+
+        this.popup.on(BI.MultiTreePopup.EVENT_AFTERINIT, function () {
+            self.trigger.getCounter().adjustView();
+            isInit = true;
+            if (want2showCounter === true) {
+                showCounter();
+            }
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: this.constants.offset
+            },
+            searcher: {
+                type: "bi.multi_tree_searcher",
+                itemsCreator: o.itemsCreator
+            },
+            switcher: {
+                el: {
+                    type: "bi.multi_tree_check_selected_button"
+                },
+                popup: {
+                    type: "bi.multi_tree_check_pane",
+                    itemsCreator: o.itemsCreator
+                }
+            }
+
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: this.popup
+        });
+
+        this.storeValue = {value: {}};
+        var change = false;
+        var clear = false;          //标识当前是否点击了清空
+
+        var isSearching = function () {
+            return self.trigger.getSearcher().isSearching();
+        };
+
+        var isPopupView = function () {
+            return self.combo.isViewVisible();
+        };
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self.storeValue = {value: self.combo.getValue()};
+            this.setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self.storeValue = {value: this.getValue()};
+            self.combo.setValue(self.storeValue);
+            BI.nextTick(function () {
+                if (isPopupView()) {
+                    self.combo.populate();
+                }
+            });
+        });
+        function showCounter() {
+            if (isSearching()) {
+                self.storeValue = {value: self.trigger.getValue()};
+            } else if (isPopupView()) {
+                self.storeValue = {value: self.combo.getValue()};
+            }
+            self.trigger.setValue(self.storeValue);
+        }
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            if (want2showCounter === false) {
+                want2showCounter = true;
+            }
+            if (isInit === true) {
+                want2showCounter = null;
+                showCounter();
+            }
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () {
+            self.combo.toggle();
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () {
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () {
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.getSearcher().hasChecked() ? {1: 1} : {}
+            };
+            this.getSearcher().setState(val);
+            this.getCounter().setButtonChecked(val);
+        });
+        this.popup.on(BI.MultiTreePopup.EVENT_CHANGE, function () {
+            change = true;
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.hasChecked() ? {1: 1} : {}
+            };
+            self.trigger.getSearcher().setState(val);
+            self.trigger.getCounter().setButtonChecked(val);
+        });
+
+        this.popup.on(BI.MultiTreePopup.EVENT_CLICK_CONFIRM, function () {
+            self._defaultState();
+        });
+        this.popup.on(BI.MultiTreePopup.EVENT_CLICK_CLEAR, function () {
+            clear = true;
+            self.setValue();
+            self._defaultState();
+        });
+
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            if (isSearching()) {
+                return;
+            }
+            if (change === true) {
+                self.storeValue = {value: self.combo.getValue()};
+                change = false;
+            }
+            self.combo.setValue(self.storeValue);
+            self.populate();
+
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () {
+            if (isSearching()) {
+                self.trigger.stopEditing();
+                self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM);
+                return;
+            }
+            if (isPopupView()) {
+                self.trigger.stopEditing();
+                self.storeValue = {value: self.combo.getValue()};
+                if (clear === true) {
+                    self.storeValue = {value: {}};
+                    clear = false;
+                    change = false;
+                }
+                self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM);
+            }
+        });
+
+        var triggerBtn = BI.createWidget({
+            type: "bi.trigger_icon_button",
+            width: o.height,
+            height: o.height,
+            cls: "multi-select-trigger-icon-button"
+        });
+        triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () {
+            self.trigger.getCounter().hideView();
+            if (self.combo.isViewVisible()) {
+                self.combo.hideView();
+            } else {
+                self.combo.showView();
+            }
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }, {
+                el: triggerBtn,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+        this.combo.hideView();
+    },
+
+    setEnable: function(v){
+        this.combo.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue.value = v || {};
+        this.combo.setValue({
+            value: v || {}
+        });
+    },
+
+    getValue: function () {
+        return this.storeValue.value;
+    },
+
+    populate: function () {
+        this.combo.populate.apply(this.combo, arguments);
+    }
+});
+
+BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM";
+
+$.shortcut('bi.multi_tree_combo', BI.MultiTreeCombo);
\ No newline at end of file
diff --git a/src/widget/multitree/multi.tree.popup.js b/src/widget/multitree/multi.tree.popup.js
new file mode 100644
index 000000000..0cda736ed
--- /dev/null
+++ b/src/widget/multitree/multi.tree.popup.js
@@ -0,0 +1,101 @@
+/**
+ * 带加载的多选下拉面板
+ * @class BI.MultiTreePopup
+ * @extends BI.Pane
+ */
+BI.MultiTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-popup',
+            maxWidth: 'auto',
+            minWidth: 100,
+            maxHeight: 250,
+            onLoaded: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.selected_values = {};
+
+        this.tree = BI.createWidget({
+            type: "bi.sync_tree",
+            height: 400,
+            cls:"popup-view-tree",
+            itemsCreator: opts.itemsCreator,
+            onLoaded: opts.onLoaded
+        });
+
+        this.popupView = BI.createWidget({
+            type: "bi.multi_popup_view",
+            element: this,
+            stopPropagation: false,
+            maxWidth: opts.maxWidth,
+            minWidth: opts.minWidth,
+            maxHeight: opts.maxHeight,
+            buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')],
+            el: this.tree
+        });
+
+        this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) {
+            switch (index) {
+                case 0:
+                    self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR);
+                    break;
+                case 1:
+                    self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM);
+                    break;
+            }
+        });
+
+        this.tree.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE);
+        });
+
+        this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT);
+        });
+
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.tree.setSelectedValue(v.value);
+    },
+
+    populate: function (config) {
+        this.tree.stroke(config);
+    },
+
+    hasChecked: function () {
+        return this.tree.hasChecked();
+    },
+
+    setEnable: function (arg) {
+        this.popupView.setEnable(arg);
+    },
+
+    resetHeight: function (h) {
+        this.popupView.resetHeight(h);
+    },
+
+    resetWidth: function (w) {
+        this.popupView.resetWidth(w);
+    }
+});
+
+BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT";
+
+
+$.shortcut('bi.multi_tree_popup_view', BI.MultiTreePopup);
\ No newline at end of file
diff --git a/src/widget/multitree/multi.tree.search.pane.js b/src/widget/multitree/multi.tree.search.pane.js
new file mode 100644
index 000000000..4ee7f3259
--- /dev/null
+++ b/src/widget/multitree/multi.tree.search.pane.js
@@ -0,0 +1,69 @@
+/**
+ *
+ * 在搜索框中输入文本弹出的面板
+ * @class BI.MultiTreeSearchPane
+ * @extends BI.Pane
+ */
+
+BI.MultiTreeSearchPane = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-multi-tree-search-pane",
+            itemsCreator: BI.emptyFn,
+            keywordGetter: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeSearchPane.superclass._init.apply(this, arguments);
+
+        var self = this, opts = this.options;
+
+        this.partTree = BI.createWidget({
+            type: "bi.part_tree",
+            element: this,
+            tipText: BI.i18nText("BI-No_Select"),
+            itemsCreator: function (op, callback) {
+                op.keyword = opts.keywordGetter();
+                opts.itemsCreator(op, callback);
+            }
+        });
+
+        this.partTree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.partTree.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE);
+        });
+    },
+
+    hasChecked: function () {
+        return this.partTree.hasChecked();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.partTree.setSelectedValue(v.value);
+    },
+
+    getValue: function () {
+        return this.partTree.getValue();
+    },
+
+    empty: function () {
+        this.partTree.empty();
+    },
+
+    populate: function (op) {
+        this.partTree.stroke.apply(this.partTree, arguments);
+    }
+});
+
+BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE";
+
+BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM";
+BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR";
+
+$.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);
\ No newline at end of file
diff --git a/src/widget/multitree/trigger/multi.tree.button.checkselected.js b/src/widget/multitree/trigger/multi.tree.button.checkselected.js
new file mode 100644
index 000000000..2315c63ce
--- /dev/null
+++ b/src/widget/multitree/trigger/multi.tree.button.checkselected.js
@@ -0,0 +1,71 @@
+/**
+ * 查看已选按钮
+ * Created by guy on 15/11/3.
+ * @class BI.MultiTreeCheckSelectedButton
+ * @extends BI.Single
+ */
+BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, {
+
+    _const: {
+        checkSelected: BI.i18nText('BI-Check_Selected')
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-check-selected-button',
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments);
+        var self = this;
+        this.indicator = BI.createWidget({
+            type: 'bi.icon_button',
+            cls: 'check-font trigger-check-selected',
+            width: 15,
+            height: 15,
+            stopPropagation: true
+        });
+
+        this.checkSelected = BI.createWidget({
+            type: 'bi.text_button',
+            cls: "trigger-check-selected",
+            invisible: true,
+            hgap: 4,
+            text: this._const.checkSelected,
+            textAlign: 'center',
+            textHeight: 15
+        });
+        this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.horizontal",
+            element: this,
+            items: [this.indicator, this.checkSelected]
+        })
+
+        this.element.hover(function () {
+            self.indicator.setVisible(false);
+            self.checkSelected.setVisible(true);
+        }, function () {
+            self.indicator.setVisible(true);
+            self.checkSelected.setVisible(false);
+        });
+        this.setVisible(false);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.setVisible(BI.size(v.value) > 0);
+    }
+});
+
+BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.multi_tree_check_selected_button', BI.MultiTreeCheckSelectedButton);
\ No newline at end of file
diff --git a/src/widget/multitree/trigger/searcher.multi.tree.js b/src/widget/multitree/trigger/searcher.multi.tree.js
new file mode 100644
index 000000000..2283a0fb8
--- /dev/null
+++ b/src/widget/multitree/trigger/searcher.multi.tree.js
@@ -0,0 +1,136 @@
+/**
+ * searcher
+ * Created by guy on 15/11/3.
+ * @class BI.MultiTreeSearcher
+ * @extends Widget
+ */
+BI.MultiTreeSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-searcher',
+            itemsCreator: BI.emptyFn,
+            popup: {},
+
+            adapter: null,
+            masker: {}
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.editor = BI.createWidget({
+            type: 'bi.multi_select_editor',
+            height: o.height,
+            el: {
+                type: "bi.simple_state_editor",
+                height: o.height
+            }
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            element: this,
+            isAutoSearch: false,
+            isAutoSync: false,
+            onSearch: function (op, callback) {
+                callback({
+                    keyword: self.editor.getValue()
+                });
+            },
+            el: this.editor,
+
+            popup: BI.extend({
+                type: "bi.multi_tree_search_pane",
+                keywordGetter: function () {
+                    return self.editor.getValue();
+                },
+                itemsCreator: function (op, callback) {
+                    op.keyword = self.editor.getValue();
+                    o.itemsCreator(op, callback);
+                }
+            }, o.popup),
+
+            adapter: o.adapter,
+            masker: o.masker
+        });
+        this.searcher.on(BI.Searcher.EVENT_START, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_START);
+        });
+        this.searcher.on(BI.Searcher.EVENT_PAUSE, function () {
+            if (this.hasMatched()) {
+
+            }
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE);
+        });
+        this.searcher.on(BI.Searcher.EVENT_STOP, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_STOP);
+        });
+        this.searcher.on(BI.Searcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiTreeSearcher.EVENT_CHANGE, arguments);
+        });
+    },
+
+    adjustView: function () {
+        this.searcher.adjustView();
+    },
+
+    isSearching: function () {
+        return this.searcher.isSearching();
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    getKeyword: function () {
+        return this.editor.getValue();
+    },
+
+    hasMatched: function () {
+        return this.searcher.hasMatched();
+    },
+
+    hasChecked: function () {
+        return this.searcher.getView() && this.searcher.getView().hasChecked();
+    },
+
+    setState: function (ob) {
+        ob || (ob = {});
+        ob.value || (ob.value = []);
+        if (ob.type === BI.Selection.All) {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All);
+        } else {
+            this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None);
+        }
+    },
+
+    setValue: function (ob) {
+        this.setState(ob);
+        this.searcher.setValue(ob);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    },
+
+    setEnable: function(v){
+        this.editor.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function (items) {
+        this.searcher.populate.apply(this.searcher, arguments);
+    }
+});
+
+BI.MultiTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+BI.MultiTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE";
+BI.MultiTreeSearcher.EVENT_START = "EVENT_START";
+BI.MultiTreeSearcher.EVENT_STOP = "EVENT_STOP";
+BI.MultiTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE";
+$.shortcut('bi.multi_tree_searcher', BI.MultiTreeSearcher);
\ No newline at end of file
diff --git a/src/widget/multitreelist/multitreelist.js b/src/widget/multitreelist/multitreelist.js
new file mode 100644
index 000000000..fb1ada71e
--- /dev/null
+++ b/src/widget/multitreelist/multitreelist.js
@@ -0,0 +1,178 @@
+/**
+ * Created by zcf on 2016/12/20.
+ */
+BI.MultiTreeList = BI.inherit(BI.Widget, {
+    constants: {
+        offset: {
+            left: 1,
+            top: 0,
+            right: 2,
+            bottom: 1
+        }
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.MultiTreeList.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-multi-tree-combo',
+            itemsCreator: BI.emptyFn,
+            height: 25
+        });
+    },
+
+    _init: function () {
+        BI.MultiTreeList.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        var isInit = false;
+        var want2showCounter = false;
+
+        this.popup = BI.createWidget({
+            type: "bi.multi_tree_list_popup",
+            itemsCreator: o.itemsCreator
+        });
+
+        this.popup.on(BI.MultiStringListPopup.EVENT_AFTER_INIT, function () {
+            self.trigger.getCounter().adjustView();
+            isInit = true;
+            if (want2showCounter === true) {
+                showCounter();
+            }
+        });
+
+        this.trigger = BI.createWidget({
+            type: "bi.multi_select_trigger",
+            height: o.height,
+            adapter: this.popup,
+            masker: {
+                offset: this.constants.offset
+            },
+            searcher: {
+                type: "bi.multi_tree_searcher",
+                itemsCreator: o.itemsCreator
+            },
+            switcher: {
+                el: {
+                    type: "bi.multi_tree_check_selected_button"
+                },
+                popup: {
+                    type: "bi.multi_tree_check_pane",
+                    itemsCreator: o.itemsCreator
+                }
+            }
+        });
+
+        this.storeValue = {value: {}};
+
+        var isSearching = function () {
+            return self.trigger.getSearcher().isSearching();
+        };
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () {
+            self.storeValue = {value: self.popup.getValue()};
+            this.setValue(self.storeValue);
+        });
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () {
+            self.storeValue = {value: this.getValue()};
+            self.trigger.setValue(self.storeValue);
+            self.popup.setValue(self.storeValue);
+            BI.nextTick(function () {
+                self.trigger.populate();
+                self.popup.populate();
+            });
+        });
+        function showCounter() {
+            if (isSearching()) {
+                self.storeValue = {value: self.trigger.getValue()};
+            } else {
+                self.storeValue = {value: self.popup.getValue()};
+            }
+            self.trigger.setValue(self.storeValue);
+        }
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () {
+            if (want2showCounter === false) {
+                want2showCounter = true;
+            }
+            if (isInit === true) {
+                want2showCounter = null;
+                showCounter();
+            }
+        });
+
+        this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () {
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.getSearcher().hasChecked() ? {1: 1} : {}
+            };
+            this.getSearcher().setState(val);
+            this.getCounter().setButtonChecked(val);
+        });
+
+        this.popup.on(BI.MultiStringListPopup.EVENT_CHANGE, function () {
+            showCounter();
+            var val = {
+                type: BI.Selection.Multi,
+                value: this.hasChecked() ? {1: 1} : {}
+            };
+            self.trigger.getSearcher().setState(val);
+            self.trigger.getCounter().setButtonChecked(val);
+            self.fireEvent(BI.MultiTreeList.EVENT_CHANGE);
+        });
+
+        var div = BI.createWidget({
+            type: "bi.layout"
+        });
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            height: "100%",
+            width: "100%",
+            items: [{
+                el: this.trigger,
+                height: 25
+            }, {
+                el: div,
+                height: 2
+            }, {
+                el: this.popup,
+                height: "fill"
+            }]
+        })
+    },
+
+    _defaultState: function () {
+        this.trigger.stopEditing();
+    },
+
+    resize: function () {
+        this.trigger.getCounter().adjustView();
+        this.trigger.getSearcher().adjustView();
+    },
+
+    setEnable: function (v) {
+        this.trigger.setEnable(v);
+        this.popup.setEnable(v);
+    },
+
+    setValue: function (v) {
+        this.storeValue.value = v || {};
+        this.popup.setValue({
+            value: v || {}
+        });
+        this.trigger.setValue({
+            value: v || {}
+        });
+    },
+
+    getValue: function () {
+        return this.storeValue.value;
+    },
+
+    populate: function () {
+        this.trigger.populate.apply(this.trigger, arguments);
+        this.popup.populate.apply(this.popup, arguments);
+    }
+});
+BI.MultiTreeList.EVENT_CHANGE = "MultiTreeList.EVENT_CHANGE";
+$.shortcut('bi.multi_tree_list', BI.MultiTreeList);
\ No newline at end of file
diff --git a/src/widget/multitreelist/multitreelist.popup.js b/src/widget/multitreelist/multitreelist.popup.js
new file mode 100644
index 000000000..9db3aebc5
--- /dev/null
+++ b/src/widget/multitreelist/multitreelist.popup.js
@@ -0,0 +1,48 @@
+/**
+ * Created by zcf on 2016/12/21.
+ */
+BI.MultiStringListPopup=BI.inherit(BI.Widget,{
+    _defaultConfig:function () {
+        return BI.extend(BI.MultiStringListPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-list-popup",
+            itemsCreator: BI.emptyFn
+        });
+    },
+    _init:function () {
+        BI.MultiStringListPopup.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.popup = BI.createWidget({
+            type: "bi.sync_tree",
+            height: 400,
+            element: this,
+            itemsCreator: o.itemsCreator
+        });
+        this.popup.on(BI.TreeView.EVENT_AFTERINIT, function () {
+            self.fireEvent(BI.MultiStringListPopup.EVENT_AFTER_INIT)
+        });
+        this.popup.on(BI.TreeView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.MultiStringListPopup.EVENT_CHANGE)
+        });
+    },
+
+    hasChecked: function () {
+        return this.popup.hasChecked();
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.popup.setValue(v.value);
+    },
+
+    populate: function (config) {
+        this.popup.stroke(config);
+    }
+
+});
+BI.MultiStringListPopup.EVENT_AFTER_INIT="BI.MultiStringListPopup.EVENT_AFTER_INIT";
+BI.MultiStringListPopup.EVENT_CHANGE="BI.MultiStringListPopup.EVENT_CHANGE";
+$.shortcut("bi.multi_tree_list_popup",BI.MultiStringListPopup);
\ No newline at end of file
diff --git a/src/widget/numericalinterval/numericalinterval.js b/src/widget/numericalinterval/numericalinterval.js
new file mode 100644
index 000000000..1592bb4cb
--- /dev/null
+++ b/src/widget/numericalinterval/numericalinterval.js
@@ -0,0 +1,535 @@
+//小于号的值为:0,小于等于号的值为:1
+//closeMIn:最小值的符号,closeMax:最大值的符号
+/**
+ * Created by roy on 15/9/17.
+ *
+ */
+BI.NumericalInterval = BI.inherit(BI.Single, {
+    constants: {
+        typeError: "typeBubble",
+        numberError: "numberBubble",
+        signalError: "signalBubble",
+        editorWidth: 114,
+        columns: 5,
+        width: 30,
+        rows: 1,
+        numberErrorCls: "number-error",
+        border: 1,
+        less: 0,
+        less_equal: 1,
+        numTip: ""
+    },
+    _defaultConfig: function () {
+        var conf = BI.NumericalInterval.superclass._defaultConfig.apply(this, arguments)
+        return BI.extend(conf, {
+            extraCls: "bi-numerical-interval",
+            height: 25
+
+        })
+    },
+    _init: function () {
+        var self = this, c = this.constants, o = this.options;
+        BI.NumericalInterval.superclass._init.apply(this, arguments)
+        this.smallEditor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height - 2,
+            watermark: BI.i18nText("BI-Unrestricted"),
+            allowBlank: true,
+            value: o.min,
+            level: "warning",
+            tipType: "warning",
+            quitChecker: function () {
+                return false;
+            },
+            validationChecker: function (v) {
+                if (!BI.isNumeric(v)) {
+                    self.smallEditorBubbleType = c.typeError;
+                    return false;
+                }
+                return true;
+            },
+            cls: "numerical-interval-small-editor"
+        });
+
+        this.smallTip = BI.createWidget({
+            type: "bi.label",
+            text: o.numTip,
+            height: o.height - 2,
+            invisible: true
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.smallEditor.element,
+            items: [{
+                el: this.smallTip,
+                top: 0,
+                right: 5
+            }]
+        });
+
+        this.bigEditor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height - 2,
+            watermark: BI.i18nText("BI-Unrestricted"),
+            allowBlank: true,
+            value: o.max,
+            level: "warning",
+            tipType: "warning",
+            quitChecker: function () {
+                return false;
+            },
+            validationChecker: function (v) {
+                if (!BI.isNumeric(v)) {
+                    self.bigEditorBubbleType = c.typeError;
+                    return false;
+                }
+                return true;
+            },
+            cls: "numerical-interval-big-editor"
+        });
+
+        this.bigTip = BI.createWidget({
+            type: "bi.label",
+            text: o.numTip,
+            height: o.height - 2,
+            invisible: true
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.bigEditor.element,
+            items: [{
+                el: this.bigTip,
+                top: 0,
+                right: 5
+            }]
+        });
+
+        //this.smallCombo = BI.createWidget({
+        //    type: "bi.numerical_interval_combo",
+        //    cls: "numerical-interval-small-combo",
+        //    height: o.height,
+        //    value: o.closemin ? 1 : 0,
+        //    offsetStyle: "left"
+        //});
+        //
+        //this.bigCombo = BI.createWidget({
+        //    type: "bi.numerical_interval_combo",
+        //    cls: "numerical-interval-big-combo",
+        //    height: o.height,
+        //    value: o.closemax ? 1 : 0,
+        //    offsetStyle: "left"
+        //});
+        this.smallCombo = BI.createWidget({
+            type: "bi.icon_combo",
+            cls: "numerical-interval-small-combo",
+            height: o.height - 2,
+            items: [{
+                text: "(" + BI.i18nText("BI-Less_Than") + ")",
+                iconClass: "less-font",
+                value: 0
+            }, {
+                text: "(" + BI.i18nText("BI-Less_And_Equal") + ")",
+                value: 1,
+                iconClass: "less-equal-font"
+            }]
+        });
+        if (o.closemin === true) {
+            this.smallCombo.setValue(1);
+        } else {
+            this.smallCombo.setValue(0);
+        }
+        this.bigCombo = BI.createWidget({
+            type: "bi.icon_combo",
+            cls: "numerical-interval-big-combo",
+            height: o.height - 2,
+            items: [{
+                text: "(" + BI.i18nText("BI-Less_Than") + ")",
+                iconClass: "less-font",
+                value: 0
+            }, {
+                text: "(" + BI.i18nText("BI-Less_And_Equal") + ")",
+                value: 1,
+                iconClass: "less-equal-font"
+            }]
+        });
+        if (o.closemax === true) {
+            this.bigCombo.setValue(1);
+        } else {
+            this.bigCombo.setValue(0);
+        }
+        this.label = BI.createWidget({
+            type: "bi.label",
+            text: BI.i18nText("BI-Value"),
+            textHeight: o.height - c.border * 2,
+            width: c.width - c.border * 2,
+            height: o.height - c.border * 2,
+            level: "warning",
+            tipType: "warning"
+        });
+        this.left = BI.createWidget({
+            type: "bi.htape",
+            items: [{
+                el: self.smallEditor
+            }, {
+                el: self.smallCombo,
+                width: c.width - c.border * 2
+            }]
+
+        });
+        this.right = BI.createWidget({
+            type: "bi.htape",
+            items: [{
+                el: self.bigCombo,
+                width: c.width - c.border * 2
+            }, {
+                el: self.bigEditor
+            }]
+        });
+
+
+        BI.createWidget({
+            element: self,
+            type: "bi.center",
+            hgap: 15,
+            height: o.height,
+            items: [
+                {
+                    type: "bi.absolute",
+                    items: [{
+                        el: self.left,
+                        left: -15,
+                        right: 0,
+                        top: 0,
+                        bottom: 0
+                    }]
+                }, {
+                    type: "bi.absolute",
+                    items: [{
+                        el: self.right,
+                        left: 0,
+                        right: -15,
+                        top: 0,
+                        bottom: 0
+                    }]
+                }
+            ]
+        });
+
+        BI.createWidget({
+            element: self,
+            type: "bi.horizontal_auto",
+            items: [
+                self.label
+            ]
+        });
+
+
+        self._setValidEvent(self.bigEditor, c.bigEditor);
+        self._setValidEvent(self.smallEditor, c.smallEditor);
+        self._setErrorEvent(self.bigEditor, c.bigEditor);
+        self._setErrorEvent(self.smallEditor, c.smallEditor);
+        self._setBlurEvent(self.bigEditor);
+        self._setBlurEvent(self.smallEditor);
+        self._setFocusEvent(self.bigEditor);
+        self._setFocusEvent(self.smallEditor);
+        self._setComboValueChangedEvent(self.bigCombo);
+        self._setComboValueChangedEvent(self.smallCombo);
+        self._setEditorValueChangedEvent(self.bigEditor);
+        self._setEditorValueChangedEvent(self.smallEditor);
+    },
+
+    _checkValidation: function () {
+        var self = this, c = this.constants, o = this.options;
+        self._setTitle("");
+        BI.Bubbles.hide(c.typeError);
+        BI.Bubbles.hide(c.numberError);
+        BI.Bubbles.hide(c.signalError);
+        if (!self.smallEditor.isValid() || !self.bigEditor.isValid()) {
+            self.element.removeClass("number-error");
+            o.validation = "invalid";
+            return c.typeError;
+        } else {
+            if (BI.isEmptyString(self.smallEditor.getValue()) || BI.isEmptyString(self.bigEditor.getValue())) {
+                self.element.removeClass("number-error");
+                o.validation = "valid";
+                return "";
+            } else {
+                var smallValue = parseFloat(self.smallEditor.getValue()), bigValue = parseFloat(self.bigEditor.getValue()),
+                    bigComboValue = self.bigCombo.getValue(), smallComboValue = self.smallCombo.getValue();
+                if (bigComboValue[0] === c.less_equal && smallComboValue[0] === c.less_equal) {
+                    if (smallValue > bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.numberError;
+                    } else {
+                        self.element.removeClass("number-error");
+                        o.validation = "valid";
+                        return "";
+                    }
+                } else {
+                    if (smallValue > bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.numberError;
+                    } else if (smallValue === bigValue) {
+                        self.element.addClass("number-error");
+                        o.validation = "invalid";
+                        return c.signalError;
+                    } else {
+                        self.element.removeClass("number-error");
+                        o.validation = "valid";
+                        return "";
+                    }
+                }
+            }
+
+        }
+    },
+
+    _setTitle: function (v) {
+        var self = this;
+        self.bigEditor.setTitle(v);
+        self.smallEditor.setTitle(v);
+        self.label.setTitle(v);
+    },
+
+    _setFocusEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self._setTitle("");
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                default :
+                    return
+            }
+
+        })
+    },
+    _setBlurEvent: function (w) {
+        var c = this.constants, self = this;
+        w.on(BI.SignEditor.EVENT_BLUR, function () {
+            BI.Bubbles.hide(c.typeError);
+            BI.Bubbles.hide(c.numberError);
+            BI.Bubbles.hide(c.signalError);
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data"));
+                    break;
+                case c.numberError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value"));
+                    break;
+                case c.signalError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value"));
+                    break;
+                default:
+                    self._setTitle("");
+            }
+        })
+    },
+
+    _setErrorEvent: function (w) {
+        var c = this.constants, self = this
+        w.on(BI.SignEditor.EVENT_ERROR, function () {
+            self._checkValidation();
+            BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                offsetStyle: "center"
+            });
+            self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+        })
+    },
+
+
+    _setValidEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_VALID, function () {
+            switch (self._checkValidation()) {
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                default:
+                    self.fireEvent(BI.NumericalInterval.EVENT_VALID);
+            }
+        })
+    },
+
+
+    _setEditorValueChangedEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.SignEditor.EVENT_CHANGE, function () {
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.numberError:
+                    BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                case c.signalError:
+                    BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, {
+                        offsetStyle: "center"
+                    });
+                    break;
+                default :
+                    break;
+            }
+            self.fireEvent(BI.NumericalInterval.EVENT_CHANGE);
+        });
+    },
+
+    _setComboValueChangedEvent: function (w) {
+        var self = this, c = this.constants;
+        w.on(BI.IconCombo.EVENT_CHANGE, function () {
+            switch (self._checkValidation()) {
+                case c.typeError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.numberError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                case c.signalError:
+                    self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value"));
+                    self.fireEvent(BI.NumericalInterval.EVENT_ERROR);
+                    break;
+                default :
+                    self.fireEvent(BI.NumericalInterval.EVENT_CHANGE);
+                    self.fireEvent(BI.NumericalInterval.EVENT_VALID);
+            }
+        })
+    },
+
+
+    isValid: function () {
+        return this.options.validation === "valid";
+    },
+
+    setEnable: function (b) {
+        this.smallEditor.setEnable(b);
+        this.smallCombo.setEnable(b);
+        this.bigEditor.setEnable(b);
+        this.bigCombo.setEnable(b);
+    },
+
+    setMinEnable: function (b) {
+        this.smallEditor.setEnable(b);
+    },
+
+    setCloseMinEnable: function (b) {
+        this.smallCombo.setEnable(b);
+    },
+
+    setMaxEnable: function (b) {
+        this.bigEditor.setEnable(b);
+    },
+
+    setCloseMaxEnable: function (b) {
+        this.bigCombo.setEnable(b);
+    },
+
+    showNumTip: function () {
+        this.smallTip.setVisible(true);
+        this.bigTip.setVisible(true);
+    },
+
+    hideNumTip: function () {
+        this.smallTip.setVisible(false);
+        this.bigTip.setVisible(false);
+    },
+
+    setNumTip: function(numTip) {
+        this.smallTip.setText(numTip);
+        this.bigTip.setText(numTip);
+    },
+
+    getNumTip: function() {
+        return this.smallTip.getText();
+    },
+
+    setValue: function (data) {
+        data = data || {};
+        var self = this, combo_value;
+        if (BI.isNumeric(data.min) || BI.isEmptyString(data.min)) {
+            self.smallEditor.setValue(data.min);
+        }
+
+        if (!BI.isNotNull(data.min)) {
+            self.smallEditor.setValue("");
+        }
+
+        if (BI.isNumeric(data.max) || BI.isEmptyString(data.max)) {
+            self.bigEditor.setValue(data.max);
+        }
+
+        if (!BI.isNotNull(data.max)) {
+            self.bigEditor.setValue("");
+        }
+
+        if (!BI.isNull(data.closemin)) {
+            if (data.closemin === true) {
+                combo_value = 1
+            } else {
+                combo_value = 0
+            }
+            self.smallCombo.setValue(combo_value);
+        }
+
+        if (!BI.isNull(data.closemax)) {
+            if (data.closemax === true) {
+                combo_value = 1
+            } else {
+                combo_value = 0
+            }
+            self.bigCombo.setValue(combo_value);
+        }
+    },
+
+
+    getValue: function () {
+        var self = this, value = {}, minComboValue = self.smallCombo.getValue(), maxComboValue = self.bigCombo.getValue();
+        value.min = self.smallEditor.getValue();
+        value.max = self.bigEditor.getValue();
+        if (minComboValue[0] === 0) {
+            value.closemin = false
+        } else {
+            value.closemin = true
+        }
+
+        if (maxComboValue[0] === 0) {
+            value.closemax = false
+        } else {
+            value.closemax = true
+        }
+        return value;
+    }
+});
+BI.NumericalInterval.EVENT_CHANGE = "EVENT_CHANGE";
+BI.NumericalInterval.EVENT_VALID = "EVENT_VALID";
+BI.NumericalInterval.EVENT_ERROR = "EVENT_ERROR";
+$.shortcut("bi.numerical_interval", BI.NumericalInterval);
\ No newline at end of file
diff --git a/src/widget/pagetable/pagetable.cell.js b/src/widget/pagetable/pagetable.cell.js
new file mode 100644
index 000000000..7b25b95ac
--- /dev/null
+++ b/src/widget/pagetable/pagetable.cell.js
@@ -0,0 +1,39 @@
+/**
+ *
+ * 表格
+ *
+ * Created by GUY on 2015/9/22.
+ * @class BI.PageTableCell
+ * @extends BI.Single
+ */
+BI.PageTableCell = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.PageTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-page-table-cell",
+            text: "",
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.PageTableCell.superclass._init.apply(this, arguments);
+        var label = BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            height: this.options.height,
+            text: this.options.text,
+            title: this.options.title,
+            value: this.options.value,
+            lgap: 5,
+            rgap: 5
+        });
+
+        if (BI.isNotNull(this.options.styles) && BI.isObject(this.options.styles)) {
+            this.element.css(this.options.styles);
+        }
+    }
+});
+
+$.shortcut("bi.page_table_cell", BI.PageTableCell);
\ No newline at end of file
diff --git a/src/widget/pagetable/pagetable.js b/src/widget/pagetable/pagetable.js
new file mode 100644
index 000000000..ee12d4d81
--- /dev/null
+++ b/src/widget/pagetable/pagetable.js
@@ -0,0 +1,250 @@
+/**
+ * 分页表格
+ *
+ * Created by GUY on 2016/2/15.
+ * @class BI.PageTable
+ * @extends BI.Widget
+ */
+BI.PageTable = BI.inherit(BI.Widget, {
+
+    _const: {
+        scrollWidth: 18,
+        minScrollWidth: 100
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PageTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-page-table",
+            el: {
+                type: "bi.sequence_table"
+            },
+            pager: {
+                horizontal: {
+                    pages: false, //总页数
+                    curr: 1, //初始化当前页, pages为数字时可用
+
+                    hasPrev: BI.emptyFn,
+                    hasNext: BI.emptyFn,
+                    firstPage: 1,
+                    lastPage: BI.emptyFn
+                },
+                vertical: {
+                    pages: false, //总页数
+                    curr: 1, //初始化当前页, pages为数字时可用
+
+                    hasPrev: BI.emptyFn,
+                    hasNext: BI.emptyFn,
+                    firstPage: 1,
+                    lastPage: BI.emptyFn
+                }
+            },
+
+            itemsCreator: BI.emptyFn,
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: BI.emptyFn,
+
+            columnSize: [],
+            minColumnSize: [],
+            maxColumnSize: [],
+            headerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: [],
+
+            headerCellStyleGetter: BI.emptyFn,
+            summaryCellStyleGetter: BI.emptyFn,
+            sequenceCellStyleGetter: BI.emptyFn,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        });
+    },
+
+    _init: function () {
+        BI.PageTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.hCurr = 1;
+        this.vCurr = 1;
+
+        this.table = BI.createWidget(o.el, {
+            type: "bi.sequence_table",
+            width: o.width,
+            height: o.height - 30,
+
+            isNeedResize: true,
+            isResizeAdapt: false,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: o.columnSize,
+            minColumnSize: o.minColumnSize,
+            maxColumnSize: o.maxColumnSize,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter,
+
+            header: o.header,
+            items: o.items,
+            //交叉表头
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems
+        });
+
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () {
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+
+        this.pager = BI.createWidget(o.pager, {
+            type: "bi.direction_pager",
+            height: 30
+        });
+        this.pager.on(BI.Pager.EVENT_CHANGE, function () {
+            var vpage = this.getVPage && this.getVPage();
+            if (BI.isNull(vpage)) {
+                vpage = this.getCurrentPage();
+            }
+            var hpage = this.getHPage && this.getHPage();
+            o.itemsCreator({
+                vpage: vpage,
+                hpage: hpage
+            }, function (items, header, crossItems, crossHeader) {
+                self.table.setVPage ? self.table.setVPage(vpage) : self.table.setCurrentPage(vpage);
+                self.table.setHPage && self.table.setHPage(hpage);
+                self.populate.apply(self, arguments);
+            });
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.table,
+                left: 0,
+                top: 0
+            }, {
+                el: this.pager,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        })
+    },
+
+    setHPage: function (v) {
+        this.hCurr = v;
+        this.pager.setHPage && this.pager.setHPage(v);
+        this.table.setHPage && this.table.setHPage(v);
+    },
+
+    setVPage: function (v) {
+        this.vCurr = v;
+        this.pager.setVPage && this.pager.setVPage(v);
+        this.table.setVPage && this.table.setVPage(v);
+    },
+
+    getHPage: function () {
+        var hpage = this.pager.getHPage && this.pager.getHPage();
+        if (BI.isNotNull(hpage)) {
+            return hpage;
+        }
+        hpage = this.pager.getCurrentPage && this.pager.getCurrentPage();
+        if (BI.isNotNull(hpage)) {
+            return hpage;
+        }
+        return this.hpage;
+    },
+
+    getVPage: function () {
+        var vpage = this.pager.getVPage && this.pager.getVPage();
+        if (BI.isNotNull(vpage)) {
+            return vpage;
+        }
+        vpage = this.pager.getCurrentPage && this.pager.getCurrentPage();
+        if (BI.isNotNull(vpage)) {
+            return vpage;
+        }
+        return this.vpage;
+    },
+
+    setWidth: function (width) {
+        BI.PageTable.superclass.setWidth.apply(this, arguments);
+        this.table.setWidth(width);
+    },
+
+    setHeight: function (height) {
+        BI.PageTable.superclass.setHeight.apply(this, arguments);
+        this.table.setHeight(height - 30);
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    restore: function () {
+        this.table.restore();
+    },
+
+    attr: function () {
+        BI.PageTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+    },
+
+    populate: function () {
+        this.pager.populate();
+        this.table.populate.apply(this.table, arguments);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        this.pager && this.pager.destroy();
+        BI.PageTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.page_table', BI.PageTable);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/datecombo/combo.param.date.js b/src/widget/paramsettingcombo/datecombo/combo.param.date.js
new file mode 100644
index 000000000..d3c3ef2e7
--- /dev/null
+++ b/src/widget/paramsettingcombo/datecombo/combo.param.date.js
@@ -0,0 +1,95 @@
+/**
+ * @class BI.DateParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.DateParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DateParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.date_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.DateParamCombo.hideView();
+        });
+
+        this.DateParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.DateParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.DateParamCombo.EVENT_CONFIRM);
+        });
+
+        this.DateParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+        BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Quarter_De");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_De");
+            case BICst.YEAR_WEEK:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Week_De");
+            case BICst.YEAR_DAY:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Day_De");
+            case BICst.MONTH_WEEK:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Week_De");
+            case BICst.MONTH_DAY:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Day_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.DateParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.DateParamCombo.superclass.setEnable.apply(this, arguments);
+        this.DateParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.DateParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.DateParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.date_param_combo", BI.DateParamCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/datecombo/popup.param.date.js b/src/widget/paramsettingcombo/datecombo/popup.param.date.js
new file mode 100644
index 000000000..53b13d996
--- /dev/null
+++ b/src/widget/paramsettingcombo/datecombo/popup.param.date.js
@@ -0,0 +1,52 @@
+/**
+ * 普通控件
+ *
+ * @class BI.DateParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.DateParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-date-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.DateParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param3_date_item",
+            value: BICst.YEAR,
+            selected: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_QUARTER,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_MONTH,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_DAY,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.MONTH_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.MONTH_DAY,
+            disabled: true
+        }]
+    }
+});
+BI.DateParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.date_param_popup_view', BI.DateParamPopupView);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.js b/src/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.js
new file mode 100644
index 000000000..5e243256b
--- /dev/null
+++ b/src/widget/paramsettingcombo/dateintervalcombo/combo.param.dateinterval.js
@@ -0,0 +1,95 @@
+/**
+ * @class BI.DateIntervalParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.DateIntervalParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.DateIntervalParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-date-interval-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.DateIntervalParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.date_interval_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.DateIntervalParamCombo.hideView();
+        });
+
+        this.DateIntervalParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.DateIntervalParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.DateIntervalParamCombo.EVENT_CONFIRM);
+        });
+
+        this.DateIntervalParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Basic_Quarter");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_Fen");
+            case BICst.YEAR_WEEK:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Week");
+            case BICst.YEAR_DAY:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Day_De");
+            case BICst.MONTH_WEEK:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Week");
+            case BICst.MONTH_DAY:
+                return value.fvalue + BI.i18nText("BI-Basic_Month") + midText + BI.i18nText("BI-Day_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.DateIntervalParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.DateIntervalParamCombo.superclass.setEnable.apply(this, arguments);
+        this.DateIntervalParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.DateIntervalParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.DateIntervalParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.date_interval_param_combo", BI.DateIntervalParamCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/dateintervalcombo/popup.param.dateinterval.js b/src/widget/paramsettingcombo/dateintervalcombo/popup.param.dateinterval.js
new file mode 100644
index 000000000..5d02bd381
--- /dev/null
+++ b/src/widget/paramsettingcombo/dateintervalcombo/popup.param.dateinterval.js
@@ -0,0 +1,52 @@
+/**
+ * 普通控件
+ *
+ * @class BI.DateIntervalParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.DateIntervalParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.DateIntervalParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-date-interval-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.DateIntervalParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            value: BICst.YEAR,
+            selected: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_QUARTER,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_MONTH,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_DAY,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.MONTH_WEEK,
+            disabled: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.MONTH_DAY,
+            disabled: true
+        }]
+    }
+});
+BI.DateIntervalParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.date_interval_param_popup_view', BI.DateIntervalParamPopupView);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/param0.date.item.js b/src/widget/paramsettingcombo/param0.date.item.js
new file mode 100644
index 000000000..a089910cf
--- /dev/null
+++ b/src/widget/paramsettingcombo/param0.date.item.js
@@ -0,0 +1,131 @@
+/**
+ * 普通控件
+ *
+ * @class BI.Param0DateItem
+ * @extends BI.Single
+ */
+BI.Param0DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param0DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param0-date-item',
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param0DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year_Fen"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getInputValue: function () {
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return BICst.YEAR;
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+    }
+});
+
+BI.Param0DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.param0_date_item', BI.Param0DateItem);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/param1.date.item.js b/src/widget/paramsettingcombo/param1.date.item.js
new file mode 100644
index 000000000..81c972020
--- /dev/null
+++ b/src/widget/paramsettingcombo/param1.date.item.js
@@ -0,0 +1,187 @@
+/**
+ * 普通控件
+ *
+ * @class BI.Param1DateItem
+ * @extends BI.Single
+ */
+BI.Param1DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param1DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param1-date-item',
+            value: BI.Param1DateItem.YEAR_DAY,
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param1DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.secondEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.secondEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.secondCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.firstCombo.setValue(0);
+        this.secondCombo.setValue(0);
+        var textJson = this._getTextByDateType();
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: textJson.ftext,
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                el: this.secondCombo,
+                rgap: 5
+            }, this.secondEditor, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: textJson.stext,
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _getTextByDateType: function(){
+        switch (this.options.value) {
+            case BI.Param1DateItem.MONTH_WEEK:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Week_De")};
+            case BI.Param1DateItem.MONTH_DAY:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param1DateItem.YEAR_MONTH:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Month_De")};
+            case BI.Param1DateItem.YEAR_DAY:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param1DateItem.YEAR_QUARTER:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Quarter_De")};
+            case BI.Param1DateItem.YEAR_WEEK:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Week_De")};
+        }
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        v.svalue = v.svalue || o.defaultEditorValue;
+        v.soffset = v.soffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    getInputValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0],
+            svalue: this.secondEditor.getValue() || 0,
+            soffset: this.secondCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+        this.secondEditor.setValue(v.svalue);
+        this.secondCombo.setValue([v.soffset]);
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.secondEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+        this.secondCombo.setEnable(!!b);
+    }
+});
+
+BI.Param1DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+BI.extend(BI.Param1DateItem , {
+    YEAR_QUARTER: BICst.YEAR_QUARTER,
+    YEAR_MONTH: BICst.YEAR_MONTH,
+    YEAR_WEEK: BICst.YEAR_WEEK,
+    YEAR_DAY: BICst.YEAR_DAY,
+    MONTH_WEEK: BICst.MONTH_WEEK,
+    MONTH_DAY: BICst.MONTH_DAY
+});
+$.shortcut('bi.param1_date_item', BI.Param1DateItem);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/param2.date.item.js b/src/widget/paramsettingcombo/param2.date.item.js
new file mode 100644
index 000000000..753af15ed
--- /dev/null
+++ b/src/widget/paramsettingcombo/param2.date.item.js
@@ -0,0 +1,187 @@
+/**
+ * 普通控件
+ *
+ * @class BI.Param2DateItem
+ * @extends BI.Single
+ */
+BI.Param2DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param2DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param2-date-item',
+            value: BI.Param2DateItem.YEAR_DAY,
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param2DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.secondEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.secondEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.secondCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+        this.firstCombo.setValue(0);
+        this.secondCombo.setValue(0);
+        var textJson = this._getTextByDateType();
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: textJson.ftext,
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                el: this.secondCombo,
+                rgap: 5
+            }, this.secondEditor, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: textJson.stext,
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _getTextByDateType: function(){
+        switch (this.options.value) {
+            case BI.Param2DateItem.MONTH_WEEK:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Week_Of_Week")};
+            case BI.Param2DateItem.MONTH_DAY:
+                return {ftext: BI.i18nText("BI-Basic_Month"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param2DateItem.YEAR_MONTH:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Month_De_Month")};
+            case BI.Param2DateItem.YEAR_DAY:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Day_De")};
+            case BI.Param2DateItem.YEAR_QUARTER:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Quarter_Of_Quarter")};
+            case BI.Param2DateItem.YEAR_WEEK:
+                return {ftext: BI.i18nText("BI-Year"), stext: BI.i18nText("BI-Week_Of_Week")};
+        }
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        v.svalue = v.svalue || o.defaultEditorValue;
+        v.soffset = v.soffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getValue: function () {
+        return this.options.value;
+    },
+
+    getInputValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0],
+            svalue: this.secondEditor.getValue() || 0,
+            soffset: this.secondCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+        this.secondEditor.setValue(v.svalue);
+        this.secondCombo.setValue([v.soffset]);
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.secondEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+        this.secondCombo.setEnable(!!b);
+    }
+});
+
+BI.Param2DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+BI.extend(BI.Param2DateItem , {
+    YEAR_QUARTER: BICst.YEAR_QUARTER,
+    YEAR_MONTH: BICst.YEAR_MONTH,
+    YEAR_WEEK: BICst.YEAR_WEEK,
+    YEAR_DAY: BICst.YEAR_DAY,
+    MONTH_WEEK: BICst.MONTH_WEEK,
+    MONTH_DAY: BICst.MONTH_DAY
+});
+$.shortcut('bi.param2_date_item', BI.Param2DateItem);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/param3.date.item.js b/src/widget/paramsettingcombo/param3.date.item.js
new file mode 100644
index 000000000..3844b48d0
--- /dev/null
+++ b/src/widget/paramsettingcombo/param3.date.item.js
@@ -0,0 +1,131 @@
+/**
+ * 普通控件
+ *
+ * @class BI.Param3DateItem
+ * @extends BI.Single
+ */
+BI.Param3DateItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.Param3DateItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-param3-date-item',
+            width: 310,
+            height: 20,
+            selected: false,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.Param3DateItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+        this.radio = BI.createWidget({
+            type: "bi.radio",
+            selected: opts.selected
+        });
+        this.radio.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [{
+                type: "bi.center_adapt",
+                items: [this.radio],
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Multi_Date_Year_Begin"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setSelected: function (v) {
+        this.radio.setSelected(!!v);
+    },
+
+    isSelected: function () {
+        return this.radio.isSelected();
+    },
+
+    getInputValue: function () {
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    },
+
+    setInputValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return BICst.YEAR;
+    },
+
+    setEnable: function (b) {
+        this.firstEditor.setEnable(!!b);
+        this.firstCombo.setEnable(!!b);
+    }
+});
+
+BI.Param3DateItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.param3_date_item', BI.Param3DateItem);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/popup.param.js b/src/widget/paramsettingcombo/popup.param.js
new file mode 100644
index 000000000..c41373a7e
--- /dev/null
+++ b/src/widget/paramsettingcombo/popup.param.js
@@ -0,0 +1,134 @@
+/**
+ * 普通控件
+ *
+ * @class BI.ParamPopupView
+ * @extends BI.Widget
+ * @abstract
+ */
+BI.ParamPopupView = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.ParamPopupView.superclass._defaultConfig.apply(this, arguments), {});
+    },
+
+    dateConfig: function(){
+
+    },
+
+    _init: function () {
+        BI.ParamPopupView.superclass._init.apply(this, arguments);
+        var self = this;
+
+        this.radioGroup = BI.createWidget({
+            type: "bi.button_group",
+            chooseType: 0,
+            items: this.dateConfig(),
+            layouts: [{
+                type: "bi.vertical",
+                items: [{
+                    type: "bi.vertical",
+                    vgap: 5
+                }],
+                vgap: 5,
+                hgap: 5
+            }]
+        });
+
+        this.radioGroup.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.ParamPopupView.EVENT_CHANGE);
+        });
+        this.popup = BI.createWidget({
+            type: 'bi.multi_popup_view',
+            element: this,
+            el: this.radioGroup,
+            minWidth: 310,
+            stopPropagation: false
+        });
+
+        this.popup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function () {
+            self.fireEvent(BI.ParamPopupView.EVENT_CONFIRM);
+        });
+
+    },
+
+    setValue: function (v) {
+        this.radioGroup.setValue(v.type);
+        BI.each(this.radioGroup.getAllButtons(), function (i, button) {
+            if (button.isSelected()) {
+                button.setEnable(true);
+                button.setInputValue(v.value);
+            } else {
+                button.setEnable(false);
+            }
+        });
+    },
+
+    getValue: function () {
+        var button = this.radioGroup.getSelectedButtons()[0];
+        var type = button.getValue(), value = button.getInputValue();
+        return {
+            type: type,
+            value: value
+        }
+    },
+
+    getCalculationValue: function () {
+        var valueObject = this.getValue();
+        var type = valueObject.type, value = valueObject.value;
+        var fPrevOrAfter = value.foffset === 0 ? -1 : 1;
+        var sPrevOrAfter = value.soffset === 0 ? -1 : 1;
+        var start, end;
+        start = end = new Date();
+        var ydate = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), new Date().getMonth(), new Date().getDate());
+        switch (type) {
+            case BICst.YEAR:
+                start = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), 0, 1);
+                end = new Date(start.getFullYear(), 11, 31);
+                break;
+            case BICst.YEAR_QUARTER:
+                ydate = new Date().getOffsetQuarter(ydate, sPrevOrAfter * value.svalue);
+                start = ydate.getQuarterStartDate();
+                end = ydate.getQuarterEndDate();
+                break;
+            case BICst.YEAR_MONTH:
+                ydate = new Date().getOffsetMonth(ydate, sPrevOrAfter * value.svalue);
+                start = new Date(ydate.getFullYear(), ydate.getMonth(), 1);
+                end  = new Date(ydate.getFullYear(), ydate.getMonth(), (ydate.getLastDateOfMonth()).getDate());
+                break;
+            case BICst.YEAR_WEEK:
+                start = ydate.getOffsetDate(sPrevOrAfter * 7 * value.svalue);
+                end = start.getOffsetDate(7);
+                break;
+            case BICst.YEAR_DAY:
+                start = ydate.getOffsetDate(sPrevOrAfter * value.svalue);
+                end = start.getOffsetDate(1);
+                break;
+            case BICst.MONTH_WEEK:
+                var mdate = new Date().getOffsetMonth(new Date(), fPrevOrAfter * value.fvalue);
+                start = mdate.getOffsetDate(sPrevOrAfter * 7 * value.svalue);
+                end = start.getOffsetDate(7);
+                break;
+            case BICst.MONTH_DAY:
+                var mdate = new Date().getOffsetMonth(new Date(), fPrevOrAfter * value.fvalue);
+                start = mdate.getOffsetDate(sPrevOrAfter * value.svalue);
+                end = start.getOffsetDate(1);
+                break;
+        }
+        return {
+            start: start,
+            end: end
+        };
+    },
+
+    resetWidth: function(w){
+        this.popup.resetWidth(w);
+    },
+
+    resetHeight: function(h){
+        this.popup.resetHeight(h);
+    }
+});
+BI.ParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+BI.ParamPopupView.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.param_popup_view", BI.ParamPopupView);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/rangevaluecombo/rangevaluecombo.js b/src/widget/paramsettingcombo/rangevaluecombo/rangevaluecombo.js
new file mode 100644
index 000000000..d30d68e3b
--- /dev/null
+++ b/src/widget/paramsettingcombo/rangevaluecombo/rangevaluecombo.js
@@ -0,0 +1,46 @@
+/**
+ * @class BI.RangeValueCombo
+ * @extend BI.Widget
+ */
+BI.RangeValueCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.RangeValueCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-range-value-combo",
+            width: 100,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.RangeValueCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.dateRangeCombo = BI.createWidget({
+            type: "bi.text_value_combo",
+            height: o.height,
+            width: o.width,
+            items: BICst.Date_Range_FILTER_COMBO
+        });
+        this.dateRangeCombo.on(BI.TextValueCombo.EVENT_CHANGE, function(){
+            self.fireEvent(BI.RangeValueCombo.EVENT_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.default",
+            element: this,
+            items: [this.dateRangeCombo]
+        });
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.dateRangeCombo.setValue(v.type);
+    },
+
+    getValue: function () {
+        return {
+            type: this.dateRangeCombo.getValue()[0]
+        };
+    }
+});
+BI.RangeValueCombo.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.range_value_combo", BI.RangeValueCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearcombo/combo.param.year.js b/src/widget/paramsettingcombo/yearcombo/combo.param.year.js
new file mode 100644
index 000000000..c65386d52
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearcombo/combo.param.year.js
@@ -0,0 +1,99 @@
+/**
+ * @class BI.YearParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+
+        this.popup = BI.createWidget({
+            type: 'bi.multi_popup_view',
+            el: {
+                type: "bi.button_tree",
+                chooseType: BI.Selection.None,
+                items: [{
+                    type: "bi.year_param_item"
+                }],
+                layouts: [{
+                    type: "bi.vertical",
+                    vgap: 5,
+                    hgap: 5
+                }]
+            },
+            minWidth: 310,
+            maxHeight: 300,
+            stopPropagation: false
+        });
+
+        this.popup.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function () {
+            self.YearParamCombo.hideView();
+        });
+
+        this.YearParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        return v.fvalue + BI.i18nText("BI-Year") +
+            (v.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+    },
+
+    getCalculationValue: function () {
+        var value = this.YearParamCombo.getValue()[0];
+        var fPrevOrAfter = value.foffset === 0 ? -1 : 1;
+        var start = new Date((new Date().getFullYear() + fPrevOrAfter * value.fvalue), 0, 1);
+        var end = new Date(start.getFullYear(), 11, 31);
+        return {
+            start: start,
+            end: end
+        };
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.YearParamCombo.setValue(v.value);
+        this.trigger.setValue(this._getShowTextByValue(v.value));
+    },
+
+    getValue: function () {
+        return {
+            type: BICst.YEAR,
+            value: this.YearParamCombo.getValue()[0]
+        }
+    }
+
+});
+BI.YearParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_param_combo", BI.YearParamCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearcombo/param.year.item.js b/src/widget/paramsettingcombo/yearcombo/param.year.item.js
new file mode 100644
index 000000000..fa699768a
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearcombo/param.year.item.js
@@ -0,0 +1,105 @@
+/**
+ * 普通控件
+ *
+ * @class BI.YearParamItem
+ * @extends BI.Single
+ */
+BI.YearParamItem = BI.inherit(BI.Single, {
+    constants: {
+        itemHeight: 20,
+        itemWidth: 20,
+        textWidth: 40,
+        comboWidth: 45
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearParamItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-param-item',
+            width: 310,
+            height: 20,
+            defaultEditorValue: "0"
+        });
+    },
+
+    _init: function () {
+        BI.YearParamItem.superclass._init.apply(this, arguments);
+        var self = this, opts = this.options;
+
+        this.firstEditor = BI.createWidget({
+            type: 'bi.small_text_editor',
+            value: opts.defaultEditorValue,
+            validationChecker: function(v){
+                return BI.isNaturalNumber(v);
+            },
+            errorText: BI.i18nText("BI-Please_Input_Integer"),
+            width: this.constants.textWidth,
+            height: this.constants.itemHeight
+        });
+        this.firstEditor.on(BI.Controller.EVENT_CHANGE, function (v) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.firstCombo = BI.createWidget({
+            type: "bi.small_text_value_combo",
+            width: this.constants.comboWidth,
+            height: this.constants.itemHeight,
+            items: BICst.BEFORE_AFTER_COMBO
+        });
+
+        this.firstCombo.setValue(0);
+
+        BI.createWidget({
+            type: 'bi.inline',
+            element: this,
+            items: [this.firstEditor, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, this.firstCombo, {
+                type: "bi.label",
+                textAlign: "center",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Basic_De"),
+                width: this.constants.itemWidth,
+                height: this.constants.itemHeight
+            }, {
+                type: "bi.label",
+                textAlign: "left",
+                cls: 'param-label',
+                text: BI.i18nText("BI-Year_Fen"),
+                height: this.constants.itemHeight,
+                lgap: 5
+            }]
+        });
+    },
+
+    _assertValue: function(v){
+        var o = this.options;
+        if(BI.isArray(v)){
+            v = v[0];
+        }
+        v = v || {};
+        v.fvalue = v.fvalue || o.defaultEditorValue;
+        v.foffset = v.foffset || 0;
+        return v;
+    },
+
+    setValue: function (v) {
+        v = this._assertValue(v);
+        this.firstEditor.setValue(v.fvalue);
+        this.firstCombo.setValue([v.foffset]);
+    },
+
+    getValue: function(){
+        return {
+            fvalue: this.firstEditor.getValue() || 0,
+            foffset: this.firstCombo.getValue()[0]
+        };
+    }
+});
+
+BI.YearParamItem.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_param_item', BI.YearParamItem);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.js b/src/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.js
new file mode 100644
index 000000000..e3deedf7d
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearmonthcombo/combo.param.yearmonth.js
@@ -0,0 +1,86 @@
+/**
+ * @class BI.YearMonthParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearMonthParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-month-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearMonthParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.year_month_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.YearMonthParamCombo.hideView();
+        });
+
+        this.YearMonthParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearMonthParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearMonthParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearMonthParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_MONTH:
+                return value.fvalue + BI.i18nText("BI-Year") + midText + BI.i18nText("BI-Month_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.YearMonthParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.YearMonthParamCombo.superclass.setEnable.apply(this, arguments);
+        this.YearMonthParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.YearMonthParamCombo.getValue();
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.YearMonthParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_month_param_combo", BI.YearMonthParamCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearmonthcombo/popup.param.yearmonth.js b/src/widget/paramsettingcombo/yearmonthcombo/popup.param.yearmonth.js
new file mode 100644
index 000000000..d0462cdba
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearmonthcombo/popup.param.yearmonth.js
@@ -0,0 +1,31 @@
+/**
+ * 普通控件
+ *
+ * @class BI.YearMonthParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.YearMonthParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-month-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.YearMonthParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            selected: true
+        }, {
+            type: "bi.param2_date_item",
+            value: BI.Param2DateItem.YEAR_MONTH,
+            disabled: true
+        }]
+    }
+});
+BI.YearMonthParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_month_param_popup_view', BI.YearMonthParamPopupView);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.js b/src/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.js
new file mode 100644
index 000000000..2816925fe
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearseasoncombo/combo.param.yearseason.js
@@ -0,0 +1,87 @@
+/**
+ * @class BI.YearSeasonParamCombo
+ * @extend BI.Widget
+ * combo : text + icon, popup : text
+ * 参见场景dashboard布局方式选择
+ */
+BI.YearSeasonParamCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearSeasonParamCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-season-param-combo",
+            width: 130,
+            height: 30
+        })
+    },
+
+    _init: function () {
+        BI.YearSeasonParamCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.text_trigger",
+            cls: "param-trigger",
+            height: o.height - 2
+        });
+        this.popup = BI.createWidget({
+            type: "bi.year_season_param_popup_view",
+            maxHeight: 300
+        });
+
+        this.popup.on(BI.ParamPopupView.EVENT_CONFIRM, function(){
+            self.YearSeasonParamCombo.hideView();
+        });
+
+        this.YearSeasonParamCombo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: this.popup
+        });
+
+        this.YearSeasonParamCombo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            self.setValue(self.getValue());
+            self.fireEvent(BI.YearSeasonParamCombo.EVENT_CONFIRM);
+        });
+
+        this.YearSeasonParamCombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.setValue(self.getValue());
+        });
+
+    },
+
+    _getShowTextByValue: function(v){
+        v = v || {};
+        var value = v.value;
+        var midText = (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+            BI.i18nText("BI-Basic_De") + (value.soffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) + value.svalue;
+        switch (v.type) {
+            case BICst.YEAR:
+                return value.fvalue + BI.i18nText("BI-Year") +
+                    (value.foffset === 0 ? BI.i18nText("BI-Qian_First") : BI.i18nText("BI-Hou_Last")) +
+                    BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Year_Fen");
+            case BICst.YEAR_QUARTER:
+                return value.fvalue + BI.i18nText("BI-Year") + midText  + BI.i18nText("BI-Quarter_De");
+        }
+    },
+
+    setValue: function (v) {
+        this.YearSeasonParamCombo.setValue(v);
+        this.trigger.setValue(this._getShowTextByValue(v));
+    },
+
+    setEnable: function (v) {
+        BI.YearSeasonParamCombo.superclass.setEnable.apply(this, arguments);
+        this.YearSeasonParamCombo.setEnable(v);
+    },
+
+    getValue: function () {
+        return this.YearSeasonParamCombo.getValue();
+        //return BI.extend(this.popup.getCalculationValue(), this.YearSeasonParamCombo.getValue());
+    },
+
+    getCalculationValue: function(){
+        return this.popup.getCalculationValue();
+    }
+});
+BI.YearSeasonParamCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.year_season_param_combo", BI.YearSeasonParamCombo);
\ No newline at end of file
diff --git a/src/widget/paramsettingcombo/yearseasoncombo/popup.param.yearseason.js b/src/widget/paramsettingcombo/yearseasoncombo/popup.param.yearseason.js
new file mode 100644
index 000000000..89d22a87a
--- /dev/null
+++ b/src/widget/paramsettingcombo/yearseasoncombo/popup.param.yearseason.js
@@ -0,0 +1,31 @@
+/**
+ * 普通控件
+ *
+ * @class BI.YearSeasonParamPopupView
+ * @extends BI.ParamPopupView
+ */
+BI.YearSeasonParamPopupView = BI.inherit(BI.ParamPopupView, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearSeasonParamPopupView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: 'bi-year-season-param-popup'
+        });
+    },
+
+    _init: function () {
+        BI.YearSeasonParamPopupView.superclass._init.apply(this, arguments);
+    },
+
+    dateConfig: function () {
+        return [{
+            type: "bi.param0_date_item",
+            selected: true
+        }, {
+            type: "bi.param1_date_item",
+            value: BI.Param1DateItem.YEAR_QUARTER,
+            disabled: true
+        }]
+    }
+});
+BI.YearSeasonParamPopupView.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.year_season_param_popup_view', BI.YearSeasonParamPopupView);
\ No newline at end of file
diff --git a/src/widget/pathchooser/pathchooser.js b/src/widget/pathchooser/pathchooser.js
new file mode 100644
index 000000000..5d1c21b19
--- /dev/null
+++ b/src/widget/pathchooser/pathchooser.js
@@ -0,0 +1,491 @@
+/**
+ * 路径选择
+ *
+ * Created by GUY on 2015/12/4.
+ * @class BI.PathChooser
+ * @extends BI.Widget
+ */
+BI.PathChooser = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#c4c6c6",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PathChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-path-chooser",
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.PathChooser.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _createRegions: function (regions) {
+        var self = this;
+        this.regions = BI.createWidgets(BI.map(regions, function (i, region) {
+            return {
+                type: "bi.path_region",
+                title: self.texts[region] || region
+            }
+        }));
+        this.regionMap = {};
+        BI.each(regions, function (i, region) {
+            self.regionMap[region] = i;
+        });
+        this.container = BI.createWidget({
+            type: "bi.horizontal",
+            verticalAlign: "top",
+            scrollx: false,
+            scrolly: false,
+            hgap: 10,
+            items: this.regions
+        });
+        BI.createWidget({
+            type: "bi.vertical_adapt",
+            element: this,
+            scrollable: true,
+            hgap: 10,
+            items: [this.container]
+        });
+    },
+
+    getRegionIndexById: function (id) {
+        var node = this.store[id];
+        var regionType = node.get("region");
+        return this.regionMap[regionType];
+    },
+
+    _drawPath: function (start, offset, index) {
+        var self = this;
+        var starts = [];
+        if (this.start.contains(start)) {
+            starts = this.start;
+        } else {
+            starts = [start];
+        }
+
+        BI.each(starts, function (i, s) {
+            BI.each(self.radios[s], function (i, rad) {
+                rad.setSelected(false);
+            });
+            BI.each(self.lines[s], function (i, line) {
+                line.attr("stroke", self._const.lineColor);
+            });
+            BI.each(self.regionIndexes[s], function (i, idx) {
+                self.regions[idx].reset();
+            });
+        });
+
+        BI.each(this.routes[start][index], function (i, id) {
+            var regionIndex = self.getRegionIndexById(id);
+            self.regions[regionIndex].setSelect(offset + index, id);
+        });
+        var current = BI.last(this.routes[start][index]);
+
+        while (current && this.routes[current] && this.routes[current].length === 1) {
+            BI.each(this.routes[current][0], function (i, id) {
+                var regionIndex = self.getRegionIndexById(id);
+                self.regions[regionIndex].setSelect(0, id);
+            });
+            this.lines[current][0].attr("stroke", self._const.selectLineColor).toFront();
+            current = BI.last(this.routes[current][0]);
+        }
+        this.lines[start][index].attr("stroke", self._const.selectLineColor).toFront();
+        this.radios[start] && this.radios[start][index] && this.radios[start][index].setSelected(true);
+    },
+
+    _drawRadio: function (start, offset, index, x, y) {
+        var self = this;
+        var radio = BI.createWidget({
+            type: "bi.radio",
+            cls: "path-chooser-radio",
+            selected: offset + index === 0,
+            start: start,
+            index: index
+        });
+        radio.on(BI.Radio.EVENT_CHANGE, function () {
+            self._drawPath(start, offset, index);
+            self.fireEvent(BI.PathChooser.EVENT_CHANGE, start, index);
+        });
+        if (!this.radios[start]) {
+            this.radios[start] = [];
+        }
+        this.radios[start].push(radio);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [{
+                el: radio,
+                left: x - 6.5,
+                top: y - 6.5
+            }]
+        })
+    },
+
+    _drawLine: function (start, lines) {
+        var self = this;
+        if (!this.lines[start]) {
+            this.lines[start] = [];
+        }
+        if (!this.pathes[start]) {
+            this.pathes[start] = [];
+        }
+        var startRegionIndex = this.getRegionIndexById(start);
+        //start所在的位置,然后接着往下画其他的路径
+        var offset = this.regions[startRegionIndex].getIndexByValue(start);
+        BI.each(lines, function (i, line) {
+            self.pathes[start][i] = [];
+            var idx = i + offset;
+            var path = "";
+            var stop = 47.5 + 29 * idx;
+            var sleft = 50 + 100 * startRegionIndex;
+            var radioStartX = sleft, radioStartY = stop;
+            var etop = stop;
+            var endRegionIndex = self.getRegionIndexById(BI.last(line));
+            var endOffset = self.regions[endRegionIndex].getIndexByValue(BI.last(line));
+            var eleft = 50 + 100 * endRegionIndex;
+            if (self.start.contains(start)) {
+                radioStartX = sleft - 50;
+                path += "M" + (sleft - 50) + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft - 50,
+                    y: stop
+                })
+            } else if (idx === 0) {
+                radioStartX = sleft + 50;
+                path += "M" + sleft + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft,
+                    y: stop
+                })
+            } else {
+                radioStartX = sleft + 50;
+                path += "M" + sleft + "," + 47.5 + "L" + (sleft + 50) + "," + 47.5 + "L" + (sleft + 50) + "," + stop;
+                self.pathes[start][i].push({
+                    x: sleft,
+                    y: 47.5
+                });
+                self.pathes[start][i].push({
+                    x: sleft + 50,
+                    y: 47.5
+                });
+                self.pathes[start][i].push({
+                    x: sleft + 50,
+                    y: stop
+                });
+            }
+            if (idx > 0) {
+                var endY = endOffset * 29 + 47.5;
+                path += "L" + (eleft - 50) + "," + etop + "L" + (eleft - 50) + "," + endY + "L" + eleft + "," + endY;
+                self.pathes[start][i].push({
+                    x: eleft - 50,
+                    y: etop
+                });
+                self.pathes[start][i].push({
+                    x: eleft - 50,
+                    y: endY
+                });
+                self.pathes[start][i].push({
+                    x: eleft,
+                    y: endY
+                });
+            } else {
+                path += "L" + eleft + "," + etop;
+                self.pathes[start][i].push({
+                    x: eleft,
+                    y: etop
+                });
+            }
+
+            var graph = self.svg.path(path)
+                .attr({
+                    stroke: idx === 0 ? self._const.selectLineColor : self._const.lineColor,
+                    'stroke-dasharray': '-'
+                });
+            self.lines[start].push(graph);
+            if (lines.length > 1) {
+                self.lines[start][0].toFront();
+            }
+            //第一个元素无论有多少个都要显示radio
+            if (self.start.contains(start)) {
+                self.lines[self.regions[0].getValueByIndex(0)][0].toFront();
+            }
+            if (lines.length > 1 || self.start.contains(start)) {
+                self._drawRadio(start, offset, i, radioStartX, radioStartY);
+            }
+        });
+    },
+
+    _drawLines: function (routes) {
+        var self = this;
+        this.lines = {};
+        this.pathes = {};
+        this.radios = {};
+        this.regionIndexes = {};
+        BI.each(routes, function (k, route) {
+            if (!self.regionIndexes[k]) {
+                self.regionIndexes[k] = [];
+            }
+            BI.each(route, function (i, rs) {
+                BI.each(rs, function (j, id) {
+                    var regionIndex = self.getRegionIndexById(id);
+                    if (!BI.contains(self.regionIndexes[k], regionIndex)) {
+                        self.regionIndexes[k].push(regionIndex);
+                    }
+                });
+            })
+        });
+        BI.each(routes, function (k, route) {
+            self._drawLine(k, route);
+        });
+    },
+
+    _pushNodes: function (nodes) {
+        var self = this;
+        var indexes = [];
+        for (var i = 0; i < nodes.length; i++) {
+            var id = nodes[i];
+            var index = self.getRegionIndexById(id);
+            indexes.push(index);
+            var region = self.regions[index];
+            if (i === nodes.length - 1) {
+                if (!region.hasItem(id)) {
+                    region.addItem(id, self.texts[id]);
+                }
+                break;
+            }
+            if (i > 0 || self.start.contains(id)) {
+                region.addItem(id, self.texts[id]);
+            }
+        }
+        for (var i = BI.first(indexes); i < BI.last(indexes); i++) {
+            if (!BI.contains(indexes, i)) {
+                self.regions[i].addItem("");
+            }
+        }
+    },
+
+    _createNodes: function () {
+        var self = this, o = this.options;
+        this.store = {};
+        this.texts = {};
+        this.start = [];
+        this.end = [];
+        BI.each(o.items, function (i, item) {
+            self.start.push(BI.first(item).value);
+            self.end.push(BI.last(item).value);
+        });
+        this.start = BI.uniq(this.start);
+        this.end = BI.uniq(this.end);
+        var regions = [];
+        var tree = new BI.Tree();
+        var branches = {}, max = 0;
+        BI.each(o.items, function (i, items) {
+            BI.each(items, function (j, item) {
+                if (!BI.has(branches, item.value)) {
+                    branches[item.value] = 0;
+                }
+                branches[item.value]++;
+                max = Math.max(max, branches[item.value]);
+                var prev = {};
+                if (j > 0) {
+                    prev = items[j - 1];
+                }
+                var parent = self.store[prev.value || ""];
+                var node = self.store[item.value] || new BI.Node(item.value);
+                node.set(item);
+                self.store[item.value] = node;
+                self.texts[item.value] = item.text;
+                self.texts[item.region] = item.regionText;
+                parent = BI.isNull(parent) ? tree.getRoot() : parent;
+                if (parent.getChildIndex(item.value) === -1) {
+                    tree.addNode(parent, node);
+                }
+            })
+        });
+
+        //算出区域列表
+        tree.traverse(function (node) {
+            BI.each(node.getChildren(), function (i, child) {
+                if (BI.contains(regions, child.get("region"))) {
+                    var index1 = BI.indexOf(regions, node.get("region"));
+                    var index2 = BI.indexOf(regions, child.get("region"));
+                    //交换区域
+                    if (index1 > index2) {
+                        var t = regions[index2];
+                        for(var j =index2; j < index1; j++){
+                            regions[j] = regions[j+1];
+                        }
+                        regions[index1] = t;
+                    }
+                } else {
+                    regions.push(child.get("region"));
+                }
+            });
+        });
+        this._createRegions(regions);
+
+        //算出节点
+        BI.each(branches, function (k, branch) {
+            if (branch < max) {
+                delete branches[k];
+            }
+        });
+
+        //过滤节点
+        var nodes = [];
+        var n = tree.getRoot();
+        while (n && n.getChildrenLength() === 1) {
+            if (BI.has(branches, n.getChildren()[0].id)) {
+                delete branches[n.getChildren()[0].id];
+                n = n.getChildren()[0];
+            } else {
+                n = null;
+            }
+        }
+        tree.traverse(function (node) {
+            if (BI.has(branches, node.id)) {
+                nodes.push(node.id);
+                delete branches[node.id];
+            }
+        });
+
+        //填充节点
+        var routes = {};
+        var s, e;
+        for (var i = 0, len = nodes.length; i < len + 1; i++) {
+            if (len === 0) {
+                s = [];
+                BI.each(this.start, function (i, id) {
+                    s.push(tree.search(id));
+                });
+                e = [];
+                BI.each(this.end, function (i, id) {
+                    e.push(tree.search(id));
+                });
+            } else if (i === len) {
+                s = e;
+                e = [];
+                BI.each(this.end, function (i, id) {
+                    e.push(tree.search(id));
+                });
+            } else if (i === 0) {
+                s = [];
+                BI.each(this.start, function (i, id) {
+                    s.push(tree.search(id));
+                });
+                e = [tree.search(nodes[i])];
+            } else {
+                s = [tree.search(e[0] || tree.getRoot(), nodes[i - 1])];
+                e = [tree.search(s[0], nodes[i])];
+            }
+            BI.each(s, function (i, n) {
+                tree._recursion(n, [n.id], function (node, route) {
+                    if (e.contains(node)) {
+                        if (!routes[n.id]) {
+                            routes[n.id] = [];
+                        }
+                        routes[n.id].push(route);
+                        self._pushNodes(route);
+                        if (e.length <= 1) {
+                            return true;
+                        }
+                    }
+                })
+            });
+        }
+        this.routes = routes;
+        this._drawLines(routes);
+    },
+
+    _unselectAllPath: function () {
+        var self = this;
+        BI.each(this.radios, function (idx, rad) {
+            BI.each(rad, function (i, r) {
+                r.setSelected(false);
+            });
+        });
+        BI.each(this.lines, function (idx, line) {
+            BI.each(line, function (i, li) {
+                li.attr("stroke", self._const.lineColor);
+            });
+        });
+        BI.each(this.regions, function (idx, region) {
+            region.reset();
+        });
+    },
+
+    populate: function (items) {
+        this.options.items = items || [];
+        var self = this;
+        this.empty();
+        if (this.options.items.length <= 0) {
+            return;
+        }
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+        this._createNodes();
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: [{
+                el: this.svg,
+                top: 0,
+                left: 0,
+                right: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        this._unselectAllPath();
+        var nodes = BI.keys(this.routes), self = this;
+        var result = [], array = [];
+        BI.each(v, function (i, val) {
+            if (BI.contains(nodes, val)) {
+                if (array.length > 0) {
+                    array.push(val);
+                    result.push(array);
+                    array = [];
+                }
+            }
+            array.push(val);
+        });
+        if (array.length > 0) {
+            result.push(array);
+        }
+        //画这n条路径
+        BI.each(result, function (idx, path) {
+            var start = path[0];
+            var index = BI.findIndex(self.routes[start], function (idx, p) {
+                if (BI.isEqual(path, p)) {
+                    return true;
+                }
+            });
+            if (index >= 0) {
+                var startRegionIndex = self.getRegionIndexById(start);
+                var offset = self.regions[startRegionIndex].getIndexByValue(start);
+                self._drawPath(start, offset, index);
+            }
+        });
+    },
+
+    getValue: function () {
+        var path = [];
+        BI.each(this.regions, function (i, region) {
+            var val = region.getValue();
+            if (BI.isKey(val)) {
+                path.push(val);
+            }
+        });
+        return path;
+    }
+});
+BI.PathChooser.EVENT_CHANGE = "PathChooser.EVENT_CHANGE";
+$.shortcut("bi.path_chooser", BI.PathChooser);
\ No newline at end of file
diff --git a/src/widget/pathchooser/pathregion.js b/src/widget/pathchooser/pathregion.js
new file mode 100644
index 000000000..195a37ee6
--- /dev/null
+++ b/src/widget/pathchooser/pathregion.js
@@ -0,0 +1,115 @@
+/**
+ * 路径选择区域
+ *
+ * Created by GUY on 2015/12/4.
+ * @class BI.PathRegion
+ * @extends BI.Widget
+ */
+BI.PathRegion = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PathRegion.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-path-region",
+            width: 80,
+            title: ""
+        })
+    },
+
+    _init: function () {
+        BI.PathRegion.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.zIndex = 100;
+        var title = BI.createWidget({
+            type: "bi.label",
+            text: o.title,
+            title: o.title,
+            height: 30
+        });
+        title.element.css("zIndex", this.zIndex--);
+        this.items = [];
+        this.vertical = BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            bgap: 5,
+            hgap: 10,
+            items: [title]
+        })
+    },
+
+    hasItem: function (val) {
+        return BI.any(this.items, function (i, item) {
+            return val === item.getValue();
+        });
+    },
+
+    addItem: function (value, text) {
+        if (BI.isKey(value)) {
+            var label = BI.createWidget({
+                type: "bi.label",
+                cls: "path-region-label",
+                text: text,
+                value: value,
+                title: text || value,
+                height: 22
+            });
+        } else {
+            var label = BI.createWidget({
+                type: "bi.layout",
+                height: 24
+            });
+        }
+        label.element.css("zIndex", this.zIndex--);
+        this.items.push(label);
+        this.vertical.addItem(label);
+        if (this.items.length === 1) {
+            this.setSelect(0, value);
+        }
+    },
+
+    reset: function () {
+        BI.each(this.items, function (i, item) {
+            item.element.removeClass("active");
+        });
+    },
+
+    setSelect: function (index, value) {
+        this.reset();
+        if (this.items.length <= 0) {
+            return;
+        }
+        if (this.items.length === 1) {
+            this.items[0].element.addClass("active");
+            return;
+        }
+        if (this.items[index].attr("value") === value) {
+            this.items[index].element.addClass("active");
+        }
+    },
+
+    setValue: function (value) {
+        this.setSelect(this.getIndexByValue(value), value);
+    },
+
+    getValueByIndex: function (idx) {
+        return this.items[idx].attr("value");
+    },
+
+    getIndexByValue: function (value) {
+        return BI.findIndex(this.items, function (i, item) {
+            return item.attr("value") === value;
+        });
+    },
+
+    getValue: function () {
+        var res;
+        BI.any(this.items, function (i, item) {
+            if (item.element.hasClass("active")) {
+                res = item.getValue();
+                return true;
+            }
+        });
+        return res;
+    }
+});
+BI.PathRegion.EVENT_CHANGE = "PathRegion.EVENT_CHANGE";
+$.shortcut("bi.path_region", BI.PathRegion);
\ No newline at end of file
diff --git a/src/widget/previewtable/previewtable.cell.js b/src/widget/previewtable/previewtable.cell.js
new file mode 100644
index 000000000..c4c93eb52
--- /dev/null
+++ b/src/widget/previewtable/previewtable.cell.js
@@ -0,0 +1,32 @@
+/**
+ * 预览表列
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTableCell
+ * @extends BI.Widget
+ */
+BI.PreviewTableCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTableCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTableCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.preview_table_cell', BI.PreviewTableCell);
\ No newline at end of file
diff --git a/src/widget/previewtable/previewtable.header.cell.js b/src/widget/previewtable/previewtable.header.cell.js
new file mode 100644
index 000000000..d026c3794
--- /dev/null
+++ b/src/widget/previewtable/previewtable.header.cell.js
@@ -0,0 +1,32 @@
+/**
+ * 预览表
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTableHeaderCell
+ * @extends BI.Widget
+ */
+BI.PreviewTableHeaderCell = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTableHeaderCell.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table-header-cell",
+            text: ""
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTableHeaderCell.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        BI.createWidget({
+            type: "bi.label",
+            element: this,
+            textAlign: "left",
+            whiteSpace: "normal",
+            height: this.options.height,
+            text: this.options.text,
+            value: this.options.value
+        })
+    }
+});
+$.shortcut('bi.preview_table_header_cell', BI.PreviewTableHeaderCell);
\ No newline at end of file
diff --git a/src/widget/previewtable/previewtable.js b/src/widget/previewtable/previewtable.js
new file mode 100644
index 000000000..5bcedf302
--- /dev/null
+++ b/src/widget/previewtable/previewtable.js
@@ -0,0 +1,209 @@
+/**
+ * 预览表
+ *
+ * Created by GUY on 2015/12/25.
+ * @class BI.PreviewTable
+ * @extends BI.Widget
+ */
+BI.PreviewTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.PreviewTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-preview-table",
+            isNeedFreeze: false,
+            freezeCols: [],
+            rowSize: null,
+            columnSize: [],
+            headerRowSize: 30,
+            header: [],
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.PreviewTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            element: this,
+            isNeedResize: false,
+
+            isResizeAdapt: false,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            rowSize: o.rowSize,
+            columnSize: o.columnSize,
+            headerRowSize: o.headerRowSize,
+
+            header: BI.map(o.header, function (i, items) {
+                return BI.map(items, function (j, item) {
+                    return BI.extend({
+                        type: "bi.preview_table_header_cell"
+                    }, item);
+                });
+            }),
+            items: BI.map(o.items, function (i, items) {
+                return BI.map(items, function (j, item) {
+                    return BI.extend({
+                        type: "bi.preview_table_cell"
+                    }, item);
+                });
+            })
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            self._adjustColumns();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            self._adjustColumns();
+        });
+    },
+
+    //是否有自适应调节的列,即列宽为""
+    _hasAdaptCol: function (columnSize) {
+        return BI.any(columnSize, function (i, size) {
+            return size === "";
+        })
+    },
+
+    _isPercentage: function (columnSize) {
+        return columnSize[0] <= 1;
+    },
+
+    _adjustColumns: function () {
+        var self = this, o = this.options;
+        if (o.isNeedFreeze === true) {
+            //如果存在百分比的情况
+            if (this._isPercentage(o.columnSize)) {
+                if (this._hasAdaptCol(o.columnSize)) {
+                    var findCols = [], remain = 0;
+                    BI.each(o.columnSize, function (i, size) {
+                        if (size === "") {
+                            findCols.push(i);
+                        } else {
+                            remain += size;
+                        }
+                    });
+                    remain = 1 - remain;
+                    var average = remain / findCols.length;
+                    BI.each(findCols, function (i, col) {
+                        o.columnSize[col] = average;
+                    });
+                }
+                var isRight = BI.first(o.freezeCols) !== 0;
+                var freezeSize = [], notFreezeSize = [];
+                BI.each(o.columnSize, function (i, size) {
+                    if (o.freezeCols.contains(i)) {
+                        freezeSize.push(size);
+                    } else {
+                        notFreezeSize.push(size);
+                    }
+                });
+                var sumFreezeSize = BI.sum(freezeSize), sumNotFreezeSize = BI.sum(notFreezeSize);
+                BI.each(freezeSize, function (i, size) {
+                    freezeSize[i] = size / sumFreezeSize;
+                });
+                BI.each(notFreezeSize, function (i, size) {
+                    notFreezeSize[i] = size / sumNotFreezeSize;
+                });
+                this.table.setRegionColumnSize(isRight ? ["fill", sumFreezeSize] : [sumFreezeSize, "fill"]);
+                this.table.setColumnSize(isRight ? (notFreezeSize.concat(freezeSize)) : (freezeSize.concat(notFreezeSize)));
+            }
+        } else {
+            //如果存在自适应宽度的列或者是百分比计算的列,需要将整个表宽设为100%
+            if (this._hasAdaptCol(o.columnSize) || this._isPercentage(o.columnSize)) {
+                this.table.setRegionColumnSize(["100%"]);
+            }
+        }
+    },
+
+    setColumnSize: function (columnSize) {
+        return this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    getCalculateColumnSize: function () {
+        return this.table.getCalculateColumnSize();
+    },
+
+    setHeaderColumnSize: function (columnSize) {
+        return this.table.setHeaderColumnSize(columnSize);
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        return this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    getCalculateRegionColumnSize: function () {
+        return this.table.getCalculateRegionColumnSize();
+    },
+
+    getCalculateRegionRowSize: function () {
+        return this.table.getCalculateRegionRowSize();
+    },
+
+    getClientRegionColumnSize: function () {
+        return this.table.getClientRegionColumnSize();
+    },
+
+    getScrollRegionColumnSize: function () {
+        return this.table.getScrollRegionColumnSize()
+    },
+
+    getScrollRegionRowSize: function () {
+        return this.table.getScrollRegionRowSize()
+    },
+
+    hasVerticalScroll: function () {
+        return this.table.hasVerticalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        return this.table.setVerticalScroll(scrollTop);
+    },
+
+    setLeftHorizontalScroll: function (scrollLeft) {
+        return this.table.setLeftHorizontalScroll(scrollLeft)
+    },
+
+    setRightHorizontalScroll: function (scrollLeft) {
+        return this.table.setRightHorizontalScroll(scrollLeft);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    getLeftHorizontalScroll: function () {
+        return this.table.getLeftHorizontalScroll();
+    },
+
+    getRightHorizontalScroll: function () {
+        return this.table.getRightHorizontalScroll();
+    },
+
+    getColumns: function () {
+        return this.table.getColumns();
+    },
+
+    populate: function (items, header) {
+        this.table.populate(items, header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.PreviewTable.superclass.destroy.apply(this, arguments);
+    }
+});
+BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE";
+$.shortcut('bi.preview_table', BI.PreviewTable);
\ No newline at end of file
diff --git a/src/widget/quarter/combo.quarter.js b/src/widget/quarter/combo.quarter.js
new file mode 100644
index 000000000..e770996d5
--- /dev/null
+++ b/src/widget/quarter/combo.quarter.js
@@ -0,0 +1,82 @@
+/**
+ * 季度下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.QuarterCombo
+ * @extends BI.Widget
+ */
+BI.QuarterCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-quarter-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.QuarterCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.storeValue = "";
+        this.trigger = BI.createWidget({
+            type: "bi.quarter_trigger"
+        });
+
+        this.trigger.on(BI.QuarterTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_CHANGE, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_START, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_STOP, function(){
+            if (!self.combo.isViewVisible()) {
+                self.combo.showView();
+            }
+        });
+        this.trigger.on(BI.QuarterTrigger.EVENT_CONFIRM, function () {
+            if(self.combo.isViewVisible()) {
+                return;
+            }
+            if(this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getKey());
+            }else if(!this.getKey()){
+                self.setValue();
+            }
+            self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM);
+        });
+        this.popup = BI.createWidget({
+            type: "bi.quarter_popup"
+        });
+
+        this.popup.on(BI.QuarterPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                el: this.popup
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue() || "";
+    }
+});
+
+BI.QuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.quarter_combo', BI.QuarterCombo);
\ No newline at end of file
diff --git a/src/widget/quarter/popup.quarter.js b/src/widget/quarter/popup.quarter.js
new file mode 100644
index 000000000..b78219aa9
--- /dev/null
+++ b/src/widget/quarter/popup.quarter.js
@@ -0,0 +1,71 @@
+/**
+ * 季度展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.QuarterPopup
+ * @extends BI.Trigger
+ */
+BI.QuarterPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-quarter-popup"
+        });
+    },
+
+    _init: function () {
+        BI.QuarterPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        var items = [{
+            text: Date._QN[01],
+            value: 1
+        }, {
+            text: Date._QN[2],
+            value: 2
+        }, {
+            text: Date._QN[3],
+            value: 3
+        }, {
+            text: Date._QN[4],
+            value: 4
+        }];
+        items = BI.map(items, function (j, item) {
+            return BI.extend(item, {
+                type: "bi.text_item",
+                cls: "bi-list-item-active",
+                textAlign: "left",
+                whiteSpace: "nowrap",
+                once: false,
+                forceSelected: true,
+                height: 25
+            });
+        });
+
+        this.quarter = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems(items, {}),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        this.quarter.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                self.fireEvent(BI.MonthPopup.EVENT_CHANGE);
+            }
+        })
+    },
+
+    getValue: function () {
+        return this.quarter.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.quarter.setValue([v]);
+    }
+});
+BI.QuarterPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.quarter_popup", BI.QuarterPopup);
\ No newline at end of file
diff --git a/src/widget/quarter/trigger.quarter.js b/src/widget/quarter/trigger.quarter.js
new file mode 100644
index 000000000..c7d5a259e
--- /dev/null
+++ b/src/widget/quarter/trigger.quarter.js
@@ -0,0 +1,106 @@
+/**
+ * 季度trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.QuarterTrigger
+ * @extends BI.Trigger
+ */
+BI.QuarterTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 30,
+        textWidth: 40,
+        errorText: BI.i18nText("BI-Quarter_Trigger_Error_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.QuarterTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-quarter-trigger",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.QuarterTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 4);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        });
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_CHANGE);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.QuarterTrigger.EVENT_CONFIRM);
+        });
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.QuarterTrigger.EVENT_STOP);
+        });
+
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        baseCls: "bi-trigger-quarter-text",
+                        text: BI.i18nText("BI-Multi_Date_Quarter"),
+                        width: c.textWidth
+                    },
+                    width: c.textWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+
+    setValue: function (v) {
+        this.editor.setState(v);
+        this.editor.setValue(v);
+        this.editor.setTitle(v);
+    },
+
+    getKey: function () {
+        return this.editor.getValue();
+    }
+});
+BI.QuarterTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.QuarterTrigger.EVENT_CHANGE = "EVENT_CHANGE";
+BI.QuarterTrigger.EVENT_START = "EVENT_START";
+BI.QuarterTrigger.EVENT_STOP = "EVENT_STOP";
+BI.QuarterTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut("bi.quarter_trigger", BI.QuarterTrigger);
\ No newline at end of file
diff --git a/src/widget/relationview/relationview.item.js b/src/widget/relationview/relationview.item.js
new file mode 100644
index 000000000..f9b679217
--- /dev/null
+++ b/src/widget/relationview/relationview.item.js
@@ -0,0 +1,59 @@
+/**
+ * 关联视图字段Item
+ *
+ * Created by GUY on 2015/12/23.
+ * @class BI.RelationViewItem
+ * @extends BI.Widget
+ */
+BI.RelationViewItem = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewItem.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-item",
+            height: 25,
+            hoverIn: BI.emptyFn,
+            hoverOut: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.element.hover(o.hoverIn, o.hoverOut);
+        var items = [];
+        if (o.isPrimary) {
+            items.push({
+                type: "bi.icon",
+                width: 16,
+                height: 16,
+                title: BI.i18nText("BI-Primary_Key")
+            });
+        }
+        items.push({
+            type: "bi.label",
+            text: o.text,
+            value: o.value,
+            height: o.height,
+            textAlign: "left",
+            width: o.isPrimary ? 70 : 90
+        });
+        BI.createWidget({
+            type: "bi.vertical_adapt",
+            element: this,
+            items: items,
+            cls: "primary-key-font",
+            lgap: 5
+        });
+    },
+
+    enableHover: function (opt) {
+        BI.RelationViewRegion.superclass.enableHover.apply(this, [{
+            container: "body"
+        }]);
+    },
+
+    setSelected: function (b) {
+        this.element[b ? "addClass" : "removeClass"]("active");
+    }
+});
+$.shortcut('bi.relation_view_item', BI.RelationViewItem);
\ No newline at end of file
diff --git a/src/widget/relationview/relationview.js b/src/widget/relationview/relationview.js
new file mode 100644
index 000000000..bb4a59539
--- /dev/null
+++ b/src/widget/relationview/relationview.js
@@ -0,0 +1,319 @@
+/**
+ * 关联视图
+ *
+ * Created by GUY on 2015/12/22.
+ * @class BI.RelationView
+ * @extends BI.Widget
+ */
+BI.RelationView = BI.inherit(BI.Widget, {
+
+    _const: {
+        lineColor: "#c4c6c6",
+        selectLineColor: "#009de3"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.RelationView.superclass._init.apply(this, arguments);
+        this.populate(this.options.items);
+    },
+
+    _calculateWidths: function () {
+        var widths = [];
+        BI.each(this.views, function (i, items) {
+            BI.each(items, function (j, obj) {
+                if (!widths[j]) {
+                    widths[j] = BI.MIN;
+                }
+                widths[j] = Math.max(widths[j], obj.getWidth());
+            })
+        });
+        return widths;
+    },
+
+    _calculateHeights: function () {
+        var heights = BI.makeArray(BI.size(this.views), BI.MIN);
+        BI.each(this.views, function (i, items) {
+            BI.each(items, function (j, obj) {
+                heights[i] = Math.max(heights[i], obj.getHeight());
+            })
+        });
+        return heights;
+    },
+
+    _hoverIn: function (target) {
+        var self = this, c = this._const;
+        BI.each(this.relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                if (relation[0].primary.value === target || relation[0].foreign.value === target) {
+                    self.lines[start][end].attr("stroke", c.selectLineColor).toFront();
+                    self.storeViews[start].setValue(relation[0].primary.value);
+                    self.storeViews[end].setValue(relation[0].foreign.value);
+                }
+            });
+        });
+    },
+
+    _hoverOut: function (target) {
+        var self = this, c = this._const;
+        BI.each(this.relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                if (relation[0].primary.value === target || relation[0].foreign.value === target) {
+                    self.lines[start][end].attr("stroke", c.lineColor);
+                    self.storeViews[start].setValue([]);
+                    self.storeViews[end].setValue([]);
+                }
+            });
+        });
+    },
+
+    previewRelationTables: function(relationTables, show) {
+        if (!show) {
+            BI.each(this.storeViews, function (i, view) {
+                view.toggleRegion(true);
+                view.setPreviewSelected(false);
+            });
+            BI.each(this.lines, function (i, lines) {
+                BI.each(lines, function (j, line) {
+                    line.show();
+                });
+            });
+            return;
+        }
+        BI.each(this.storeViews, function (id, view) {
+            if (!relationTables.contains(id)) {
+                view.toggleRegion(false);
+            } else {
+                view.setPreviewSelected(true);
+            }
+        });
+        BI.each(this.lines, function (id, lines) {
+            BI.each(lines, function (cId, line) {
+                if (!relationTables.contains(id) || !relationTables.contains(cId)) {
+                    line.hide();
+                }
+            });
+        });
+    },
+
+    populate: function (items) {
+        var self = this, o = this.options, c = this._const;
+        o.items = items || [];
+        this.empty();
+        this.svg = BI.createWidget({
+            type: "bi.svg"
+        });
+
+        //算出所有的区域和关联
+        var regions = this.regions = {}, relations = this.relations = {};
+        BI.each(items, function (i, item) {
+            var pr = item.primary.region, fr = item.foreign && item.foreign.region;
+            if (pr && !relations[pr]) {
+                relations[pr] = {};
+            }
+            if (pr && fr && !relations[pr][fr]) {
+                relations[pr][fr] = [];
+            }
+            if (pr && !regions[pr]) {
+                regions[pr] = [];
+            }
+            if (fr && !regions[fr]) {
+                regions[fr] = [];
+            }
+            if (pr && !BI.deepContains(regions[pr], item.primary)) {
+                regions[pr].push(item.primary);
+            }
+            if (fr && !BI.deepContains(regions[fr], item.foreign)) {
+                regions[fr].push(item.foreign);
+            }
+            pr && fr && relations[pr][fr].push(item);
+        });
+        //求拓扑
+        var topology = [];
+        var rs = BI.clone(regions), store = {};
+        while (!BI.isEmpty(rs)) {
+            var clone = BI.clone(rs);
+            BI.each(o.items, function (i, item) {
+                if (!store[item.primary.region]) {
+                    delete clone[item.foreign && item.foreign.region];
+                }
+            });
+            topology.push(BI.keys(clone));
+            BI.extend(store, clone);
+            BI.each(clone, function (k, v) {
+                delete rs[k];
+            });
+        }
+        //构建视图
+        var views = this.views = {}, storeViews = this.storeViews = {}, indexes = this.indexes = {};
+        var verticals = [];
+        BI.each(topology, function (i, items) {
+            if (!views[i]) {
+                views[i] = {};
+            }
+            var horizontal = [];
+            BI.each(items, function (j, region) {
+                var items = regions[region];
+                views[i][j] = storeViews[region] = BI.createWidget({
+                    type: "bi.relation_view_region_container",
+                    value: region,
+                    header: items[0].regionTitle,
+                    text: items.length > 0 ? items[0].regionText : "",
+                    handler: items.length > 0 ? items[0].regionHandler : BI.emptyFn,
+                    items: items,
+                    belongPackage: items.length > 0 ? items[0].belongPackage : true
+                });
+                if (BI.isNotNull(items[0]) && BI.isNotNull(items[0].keyword)) {
+                    views[i][j].doRedMark(items[0].keyword);
+                }
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_IN, function (v) {
+                    self._hoverIn(v);
+                });
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, function (v) {
+                    self._hoverOut(v);
+                });
+                views[i][j].on(BI.RelationViewRegionContainer.EVENT_PREVIEW, function (v) {
+                    self.fireEvent(BI.RelationView.EVENT_PREVIEW, region, v);
+                });
+                indexes[region] = {i: i, j: j};
+                horizontal.push(views[i][j]);
+            });
+            verticals.push({
+                type: "bi.horizontal",
+                items: horizontal
+            })
+        });
+
+        //求每一行的高度
+        var heights = this._calculateHeights();
+
+        //求每一列的宽度
+        var widths = this._calculateWidths();
+
+        //求相对宽度和高度
+        var offsetWidths = [0], offsetHeights = [0];
+        BI.each(heights, function (i, h) {
+            if (i === 0) {
+                return;
+            }
+            offsetHeights[i] = offsetHeights[i - 1] + heights[i - 1];
+        });
+        BI.each(widths, function (i, w) {
+            if (i === 0) {
+                return;
+            }
+            offsetWidths[i] = offsetWidths[i - 1] + widths[i - 1];
+        });
+
+        //画线
+        var lines = this.lines = {};//缓存所有的线
+        BI.each(relations, function (start, rs) {
+            BI.each(rs, function (end, relation) {
+                var startIndex = indexes[start], endIndex = indexes[end];
+                var top = 0, right = 1, bottom = 2, left = 3;
+                var startDirection = bottom, endDirection = top;
+                // if (startIndex.j > endIndex.j) {
+                //     startDirection = left;
+                //     endDirection = right;
+                // } else if (startIndex.j < endIndex.j) {
+                //     startDirection = right;
+                //     endDirection = left;
+                // } else if (startIndex.i < endIndex.i) {
+                //     startDirection = bottom;
+                //     endDirection = top;
+                // } else if (startIndex.i > endIndex.i) {
+                //     startDirection = top;
+                //     endDirection = bottom;
+                // }
+                var draw = function (i, j, direction, isForeign) {
+                    var x = offsetWidths[j] + (widths[j] - views[i][j].getWidth()) / 2;
+                    var y = offsetHeights[i] + (heights[i] - views[i][j].getHeight()) / 2;
+                    var path = "", position;
+                    switch (direction) {
+                        case top:
+                            position = isForeign ? views[i][j].getTopRightPosition() : views[i][j].getTopLeftPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + x + "," + (y - 10);
+                            y -= 10;
+                            break;
+                        case right:
+                            position = views[i][j].getRightPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + (x + 10) + "," + y;
+                            x += 10;
+                            break;
+                        case bottom:
+                            position = views[i][j].getBottomPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + x + "," + (y + 10);
+                            y += 10;
+                            break;
+                        case left:
+                            position = views[i][j].getLeftPosition();
+                            x += position.x;
+                            y += position.y;
+                            path = "M" + x + "," + y + "L" + (x - 10) + "," + y;
+                            x -= 10;
+                            break;
+                    }
+                    return {x: x, y: y, path: path};
+                };
+                var path = "";
+                var si = draw(startIndex.i, startIndex.j, startDirection);
+                var ei = draw(endIndex.i, endIndex.j, endDirection, true);
+                path += si.path + ei.path;
+                if (!lines[start]) {
+                    lines[start] = {};
+                }
+                path += "M" + si.x + "," + si.y + "L" + ei.x + "," + ei.y;
+                var line = lines[start][end] = self.svg.path(path)
+                    .attr({"stroke": c.lineColor, "stroke-width": "2"})
+                    .hover(function () {
+                        line.attr("stroke", c.selectLineColor).toFront();
+                        storeViews[start].setValue(relation[0].primary.value);
+                        storeViews[end].setValue(relation[0].foreign.value);
+                    }, function () {
+                        line.attr("stroke", c.lineColor);
+                        storeViews[start].setValue([]);
+                        storeViews[end].setValue([]);
+                    });
+            });
+        });
+        var container = BI.createWidget();
+        BI.createWidget({
+            type: "bi.vertical",
+            element: container,
+            items: verticals
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: container,
+            items: [{
+                el: this.svg,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.center_adapt",
+            scrollable: true,
+            element: this,
+            items: [container]
+        });
+    }
+});
+BI.RelationView.EVENT_CHANGE = "RelationView.EVENT_CHANGE";
+BI.RelationView.EVENT_PREVIEW = "EVENT_PREVIEW";
+$.shortcut('bi.relation_view', BI.RelationView);
\ No newline at end of file
diff --git a/src/widget/relationview/relationview.region.container.js b/src/widget/relationview/relationview.region.container.js
new file mode 100644
index 000000000..5b8aff362
--- /dev/null
+++ b/src/widget/relationview/relationview.region.container.js
@@ -0,0 +1,94 @@
+/**
+ * Created by Young's on 2017/3/10.
+ */
+BI.RelationViewRegionContainer = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewRegionContainer.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-region-container",
+            width: 150
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewRegionContainer.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.region = BI.createWidget({
+            type: "bi.relation_view_region",
+            value: o.value,
+            header: o.header,
+            text: o.text,
+            handler: o.handler,
+            items: o.items,
+            belongPackage: o.belongPackage
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_PREVIEW, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_PREVIEW, v);
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_HOVER_IN, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_IN, v);
+        });
+        this.region.on(BI.RelationViewRegion.EVENT_HOVER_OUT, function (v) {
+            self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, v);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.region],
+            width: this.region.getWidth(),
+            height: this.region.getHeight()
+        });
+    },
+
+    doRedMark: function () {
+        this.region.doRedMark.apply(this.region, arguments);
+    },
+
+    unRedMark: function () {
+        this.region.unRedMark.apply(this.region, arguments);
+    },
+
+    getWidth: function () {
+        return this.region.getWidth();
+    },
+
+    getHeight: function () {
+        return this.region.getHeight();
+    },
+
+    //获取上方开始划线的位置
+    getTopLeftPosition: function () {
+        return this.region.getTopLeftPosition();
+    },
+
+    getTopRightPosition: function () {
+        return this.region.getTopRightPosition();
+    },
+
+    getBottomPosition: function () {
+        return this.region.getBottomPosition();
+    },
+
+    getLeftPosition: function () {
+        return this.region.getLeftPosition();
+    },
+
+    getRightPosition: function () {
+        return this.region.getRightPosition();
+    },
+
+    setValue: function (v) {
+        this.region.setValue(v);
+    },
+
+    toggleRegion: function (v) {
+        v === true ? this.region.element.fadeIn() : this.region.element.fadeOut();
+    },
+
+    setPreviewSelected: function(v) {
+        this.region.setPreviewSelected(v);
+    }
+});
+BI.RelationViewRegionContainer.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN";
+BI.RelationViewRegionContainer.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT";
+BI.RelationViewRegionContainer.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW";
+$.shortcut("bi.relation_view_region_container", BI.RelationViewRegionContainer);
\ No newline at end of file
diff --git a/src/widget/relationview/relationview.region.js b/src/widget/relationview/relationview.region.js
new file mode 100644
index 000000000..02ce307e9
--- /dev/null
+++ b/src/widget/relationview/relationview.region.js
@@ -0,0 +1,157 @@
+/**
+ * 关联视图
+ *
+ * Created by GUY on 2015/12/23.
+ * @class BI.RelationViewRegion
+ * @extends BI.BasicButton
+ */
+BI.RelationViewRegion = BI.inherit(BI.BasicButton, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.RelationViewRegion.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-relation-view-region cursor-pointer",
+            width: 150,
+            text: "",
+            value: "",
+            header: "",
+            items: [],
+            belongPackage: true
+        });
+    },
+
+    _init: function () {
+        BI.RelationViewRegion.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.preview = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "relation-table-preview-font",
+            width: 25,
+            height: 25,
+            stopPropagation: true
+        });
+        this.preview.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.RelationViewRegion.EVENT_PREVIEW, this.isSelected());
+        });
+
+        this.title = BI.createWidget({
+            type: "bi.label",
+            height: 25,
+            width: 70,
+            text: o.text,
+            value: o.value,
+            textAlign: "left"
+        });
+        //title放body上
+        if (BI.isKey(o.header)) {
+            this.title.setTitle(o.header, {
+                container: "body"
+            })
+        }
+
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            items: this._createItems(o.items),
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [{
+                type: "bi.vertical",
+                cls: "relation-view-region-container " + (o.belongPackage ? "" : "other-package"),
+                items: [{
+                    type: "bi.vertical_adapt",
+                    cls: "relation-view-region-title",
+                    items: [this.preview, this.title]
+                }, this.button_group]
+            }],
+            hgap: 25,
+            vgap: 20
+        })
+    },
+
+    _createItems: function (items) {
+        var self = this;
+        return BI.map(items, function (i, item) {
+            return BI.extend(item, {
+                type: "bi.relation_view_item",
+                hoverIn: function () {
+                    self.setValue(item.value);
+                    self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_IN, item.value);
+                },
+                hoverOut: function () {
+                    self.setValue([]);
+                    self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_OUT, item.value);
+                }
+            })
+        });
+    },
+
+    doRedMark: function () {
+        this.title.doRedMark.apply(this.title, arguments);
+    },
+
+    unRedMark: function () {
+        this.title.unRedMark.apply(this.title, arguments);
+    },
+
+    getWidth: function () {
+        return this.options.width;
+    },
+
+    getHeight: function () {
+        return this.button_group.getAllButtons().length * 25 + 25 + 2 * 20 + 3;
+    },
+
+    //获取上方开始划线的位置
+    getTopLeftPosition: function () {
+        return {
+            x: 25 + 10,
+            y: 20
+        }
+    },
+
+    getTopRightPosition: function () {
+        return {
+            x: this.getWidth() - 25 - 10,
+            y: 20
+        }
+    },
+
+    getBottomPosition: function () {
+        return {
+            x: 25 + 10,
+            y: this.getHeight() - 20
+        }
+    },
+
+    getLeftPosition: function () {
+        return {
+            x: 25,
+            y: 20 + 10
+        }
+    },
+
+    getRightPosition: function () {
+        return {
+            x: this.getWidth() - 25,
+            y: 20 + 10
+        }
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    setPreviewSelected: function(v) {
+        this.preview.setSelected(v);
+    }
+});
+BI.RelationViewRegion.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN";
+BI.RelationViewRegion.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT";
+BI.RelationViewRegion.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW";
+$.shortcut('bi.relation_view_region', BI.RelationViewRegion);
\ No newline at end of file
diff --git a/src/widget/selectdata/searcher/searcher.selectdata.js b/src/widget/selectdata/searcher/searcher.selectdata.js
new file mode 100644
index 000000000..9ed7454f7
--- /dev/null
+++ b/src/widget/selectdata/searcher/searcher.selectdata.js
@@ -0,0 +1,129 @@
+/**
+ * 完成搜索功能模块
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearcher
+ * @extends BI.Widget
+ */
+BI.SelectDataSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-searcher",
+            packages: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.packagePane = BI.createWidget({
+            type: "bi.select_data_switcher",
+            packages: o.packages,
+            itemsCreator: function (op) {
+                op.packageId = self.getPackageId();
+                if (!op.packageId) {
+                    return;
+                }
+                o.itemsCreator.apply(self, arguments);
+            }
+        });
+        this.packagePane.on(BI.SelectDataSwitcher.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_PACKAGE, arguments);
+        });
+        this.packagePane.on(BI.SelectDataSwitcher.EVENT_CLICK_ITEM, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcherPane = BI.createWidget({
+            type: "bi.select_data_search_result_pane",
+            itemsCreator: function (op) {
+                op.packageId = self.getPackageId();
+                if (!op.packageId) {
+                    return;
+                }
+                o.itemsCreator.apply(self, arguments);
+            }
+        });
+        this.searcherPane.on(BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE, function () {
+            self.searcher.doSearch();
+        });
+        this.searcherPane.on(BI.SelectDataSearchResultPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(BI.extend(op, {
+                    packageId: self.getPackageId(),
+                    searchType: self.searcherPane.getSegmentValue()
+                }), function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI,
+            popup: this.searcherPane,
+            adapter: this.packagePane
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.packagePane]
+        })
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataSearcher.superclass.setEnable.apply(this, arguments);
+        this.packagePane.setEnable(v)
+    },
+
+    setPackage: function (pId) {
+        this.packagePane.setPackage(pId);
+    },
+
+    getPackageId: function () {
+        return this.packagePane.getPackageId();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populatePackages: function (packages) {
+        this.options.packages = packages;
+        this.packagePane.populatePackages(packages);
+        this.searcher.stopSearch();
+        this.populate();
+    },
+
+    populate: function () {
+        this.packagePane.populate.apply(this.packagePane, arguments);
+    }
+});
+BI.SelectDataSearcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+BI.SelectDataSearcher.EVENT_CLICK_PACKAGE = "EVENT_CLICK_PACKAGE";
+$.shortcut('bi.select_data_searcher', BI.SelectDataSearcher);
\ No newline at end of file
diff --git a/src/widget/selectdata/searchpane/result.search.selectdata.js b/src/widget/selectdata/searchpane/result.search.selectdata.js
new file mode 100644
index 000000000..9381eeef1
--- /dev/null
+++ b/src/widget/selectdata/searchpane/result.search.selectdata.js
@@ -0,0 +1,100 @@
+/**
+ * 搜索结果面板
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearchResultPane
+ * @extends BI.Widget
+ */
+BI.SelectDataSearchResultPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearchResultPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-search-result-pane bi-searcher-view",
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSearchResultPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.segment = BI.createWidget({
+            type: "bi.select_data_search_segment",
+            cls: "search-result-toolbar"
+        });
+        this.segment.on(BI.SelectDataSearchSegment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE);
+        });
+
+        this.resultPane = BI.createWidget({
+            type: "bi.searcher_view",
+            matcher: {
+                type: "bi.select_data_tree",
+                itemsCreator: o.itemsCreator
+            },
+            searcher: {
+                type: "bi.select_data_tree",
+                itemsCreator: o.itemsCreator
+            }
+        });
+        this.resultPane.on(BI.SearcherView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchResultPane.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.segment,
+                height: 60
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 2
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 1
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.resultPane,
+                    left: 0,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+    },
+
+    startSearch: function () {
+
+    },
+
+    stopSearch: function () {
+
+    },
+
+    empty: function () {
+        this.resultPane.empty();
+    },
+
+    populate: function (searchResult, matchResult, keyword) {
+        this.resultPane.populate.apply(this.resultPane, arguments);
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getSegmentValue: function () {
+        return this.segment.getValue();
+    },
+
+    getValue: function () {
+        return this.resultPane.getValue();
+    }
+});
+BI.SelectDataSearchResultPane.EVENT_CHANGE = "EVENT_CHANGE";
+BI.SelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE = "EVENT_SEARCH_TYPE_CHANGE";
+$.shortcut('bi.select_data_search_result_pane', BI.SelectDataSearchResultPane);
\ No newline at end of file
diff --git a/src/widget/selectdata/searchpane/segment.search.selectdata.js b/src/widget/selectdata/searchpane/segment.search.selectdata.js
new file mode 100644
index 000000000..2916d599e
--- /dev/null
+++ b/src/widget/selectdata/searchpane/segment.search.selectdata.js
@@ -0,0 +1,114 @@
+/**
+ * search面板选项栏
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSearchSegment
+ * @extends BI.Widget
+ */
+BI.SelectDataSearchSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSearchSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-search-segment",
+            height: 60
+        });
+    },
+
+    //创建所有数据和业务包选项
+    _createSectionTab: function () {
+        var self = this;
+        this.pack = BI.createWidget({
+            type: "bi.line_segment_button",
+            height: 24,
+            selected: true,
+            text: BI.i18nText("BI-Current_Package"),
+            value: BI.SelectDataSearchSegment.SECTION_PACKAGE
+        });
+        this.all = BI.createWidget({
+            type: "bi.line_segment_button",
+            height: 24,
+            text: BI.i18nText("BI-All_Data"),
+            value: BI.SelectDataSearchSegment.SECTION_ALL
+        });
+
+        this.button_group = BI.createWidget({
+            type: "bi.line_segment",
+            height: 25,
+            items: [this.all, this.pack]
+        });
+
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchSegment.EVENT_CHANGE);
+        });
+        return this.button_group;
+    },
+
+    _createSegmet: function () {
+        var self = this;
+        this.segment = BI.createWidget({
+            type: "bi.segment",
+            height: 20,
+            cls: "search-segment-field-table",
+            items: [{
+                text: BI.i18nText("BI-Basic_Field"),
+                selected: true,
+                value: BI.SelectDataSearchSegment.SECTION_FIELD
+            }, {
+                text: BI.i18nText("BI-Basic_Table"),
+                value: BI.SelectDataSearchSegment.SECTION_TABLE
+            }]
+        });
+        this.segment.on(BI.Segment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSearchSegment.EVENT_CHANGE);
+        });
+        return this.segment;
+    },
+
+    _init: function () {
+        BI.SelectDataSearchSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this._createSectionTab(), {
+                type: "bi.absolute",
+                height: 35,
+                items: [{
+                    el: this._createSegmet(),
+                    top: 10,
+                    right: 10,
+                    left: 10,
+                    bottom: 5
+                }]
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        var self = this;
+        BI.each([BI.SelectDataSearchSegment.SECTION_ALL,
+            BI.SelectDataSearchSegment.SECTION_PACKAGE], function (i, key) {
+            if (key & v) {
+                self.button_group.setValue(key & v);
+            }
+        });
+        BI.each([BI.SelectDataSearchSegment.SECTION_FIELD,
+            BI.SelectDataSearchSegment.SECTION_TABLE], function (i, key) {
+            if (key & v) {
+                self.segment.setValue(key & v);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.button_group.getValue()[0] | this.segment.getValue()[0]
+    }
+});
+
+BI.extend(BI.SelectDataSearchSegment, {
+    SECTION_ALL: 0x1,
+    SECTION_PACKAGE: 0x10,
+    SECTION_FIELD: 0x100,
+    SECTION_TABLE: 0x1000
+});
+BI.SelectDataSearchSegment.EVENT_CHANGE = "SelectDataSearchSegment.EVENT_CHANGE";
+$.shortcut('bi.select_data_search_segment', BI.SelectDataSearchSegment);
\ No newline at end of file
diff --git a/src/widget/selectdata/switcher/switcher.selectdata.js b/src/widget/selectdata/switcher/switcher.selectdata.js
new file mode 100644
index 000000000..7e2fca6c1
--- /dev/null
+++ b/src/widget/selectdata/switcher/switcher.selectdata.js
@@ -0,0 +1,99 @@
+/**
+ * 切换业务包
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SelectDataSwitcher
+ * @extends BI.Widget
+ */
+BI.SelectDataSwitcher = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataSwitcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-switcher",
+            packages: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataSwitcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.combo = BI.createWidget({
+            type: "bi.single_tree_combo",
+            height: 25,
+            items: o.packages
+        });
+        this.combo.on(BI.SingleTreeCombo.EVENT_CHANGE, function () {
+            self.tree.populate();
+            self.fireEvent(BI.SelectDataSwitcher.EVENT_CHANGE, arguments);
+        });
+
+        this.tree = BI.createWidget({
+            type: "bi.select_data_tree",
+            itemsCreator: function () {
+                var args = Array.prototype.slice.call(arguments, 0);
+                args[0].packageId = self.getPackageId();
+                o.itemsCreator.apply(self, args);
+            }
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataSwitcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    hgap: 10,
+                    items: [{
+                        el: this.combo
+                    }]
+                },
+                height: 30
+            }, {
+                el: this.tree
+            }]
+        });
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataSwitcher.superclass.setEnable.apply(this, arguments);
+        this.tree.setEnable(v)
+    },
+
+
+    setPackage: function (pId) {
+        this.combo.setValue([pId]);
+        this.tree.populate();
+    },
+
+    getPackageId: function () {
+        return this.combo.getValue()[0];
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    populatePackages: function (pacakges) {
+        this.options.packages = pacakges;
+        var pId = this.getPackageId();
+        this.combo.populate(pacakges);
+        if (BI.isKey(pId)) {
+            this.combo.setValue(pId);
+        }
+    }
+});
+BI.SelectDataSwitcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+BI.SelectDataSwitcher.EVENT_CHANGE = "SelectDataSwitcher.EVENT_CHANGE";
+$.shortcut('bi.select_data_switcher', BI.SelectDataSwitcher);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/expander.selectdata.js b/src/widget/selectdata/tree/expander.selectdata.js
new file mode 100644
index 000000000..62324229b
--- /dev/null
+++ b/src/widget/selectdata/tree/expander.selectdata.js
@@ -0,0 +1,93 @@
+/**
+ * 字段列表展开Expander
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataExpander
+ * @extends BI.Widget
+ */
+BI.SelectDataExpander = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-expander",
+            el: {},
+            popup: {
+                items: [],
+                itemsCreator: BI.emptyFn
+            }
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataExpander.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget(o.el);
+        this.expander = BI.createWidget({
+            type: "bi.expander",
+            element: this,
+            isDefaultInit: false,
+            el: this.trigger,
+            popup: BI.extend({
+                type: "bi.select_data_loader"
+            }, o.popup)
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.expander.on(BI.Expander.EVENT_EXPAND, function(){
+
+        });
+        this.expander.on(BI.Expander.EVENT_COLLAPSE, function(){
+            this.getView().hideView();
+        });
+        this.expander.on(BI.Expander.EVENT_AFTER_INIT, function () {
+            this.getView().populate();
+        });
+        this.expander.on(BI.Expander.EVENT_CHANGE, function () {
+            self.trigger.setValue(this.getValue());
+        });
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataExpander.superclass.setEnable.apply(this, arguments)
+        this.expander.setEnable(v);
+        this.trigger.setEnable(v)
+    },
+
+    doBehavior: function () {
+        this.trigger.doRedMark.apply(this.trigger, arguments);
+        this.expander.doBehavior.apply(this.expander, arguments);
+    },
+
+    setValue: function (v) {
+        this.expander.setValue(v);
+    },
+
+    getValue: function () {
+        return this.expander.getValue();
+    },
+
+    showView: function(b){
+        this.expander.showView();
+    },
+
+    hideView: function(){
+        this.expander.hideView();
+    },
+
+    isExpanded: function () {
+        return this.expander.isExpanded();
+    },
+
+    getAllLeaves: function () {
+        return this.expander.getAllLeaves();
+    },
+
+    getNodeById: function (id) {
+        return this.expander.getNodeById(id);
+    },
+
+    getNodeByValue: function (value) {
+        return this.expander.getNodeByValue(value);
+    }
+});
+$.shortcut("bi.select_data_expander", BI.SelectDataExpander);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/loader.selectdata.js b/src/widget/selectdata/tree/loader.selectdata.js
new file mode 100644
index 000000000..0e56cb062
--- /dev/null
+++ b/src/widget/selectdata/tree/loader.selectdata.js
@@ -0,0 +1,129 @@
+/**
+ * 字段列表
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataLoader
+ * @extends BI.Widget
+ */
+BI.SelectDataLoader = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLoader.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-loader",
+            items: [],
+            el: {},
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataLoader.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.loader = BI.createWidget({
+            type: "bi.loader",
+            isDefaultInit: false,
+            element: this,
+            items: o.items,
+            itemsCreator: o.itemsCreator,
+            el: BI.extend({
+                type: "bi.button_tree",
+                behaviors: {
+                    redmark: function () {
+                        return true;
+                    }
+                },
+                chooseType: BI.Selection.Multi,
+                layouts: [{
+                    type: "bi.vertical",
+                    hgap: 0,
+                    vgap: 0
+                }]
+            }, o.el)
+        });
+        this.loader.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            if (type === BI.Events.CLICK) {
+                if (ob.isSelected()) {
+                    var index = this.getIndexByValue(val);
+                    if (index > -1) {
+                        var alls = this.getAllButtons();
+                        if (index - 1 >= 0) {
+                            if (BI.isNotNull(alls[index - 1]) && BI.isFunction(alls[index - 1].isSelected)
+                                && alls[index - 1].isSelected()) {
+                                alls[index - 1].setBottomLineVisible();
+                                ob.setTopLineVisible();
+                            }
+                        }
+                        if (index + 1 <= alls.length - 1) {
+                            if (BI.isNotNull(alls[index + 1]) && BI.isFunction(alls[index + 1].isSelected)
+                                && alls[index + 1].isSelected()) {
+                                alls[index + 1].setTopLineVisible();
+                                ob.setBottomLineVisible();
+                            }
+                        }
+                    }
+                } else {
+                    var index = this.getIndexByValue(val);
+                    if (index > -1) {
+                        var alls = this.getAllButtons();
+                        if (index - 1 >= 0) {
+                            if (BI.isNotNull(alls[index - 1]) && BI.isFunction(alls[index - 1].isSelected)
+                                && alls[index - 1].isSelected()) {
+                                alls[index - 1].setBottomLineInVisible();
+                            }
+                        }
+                        if (index + 1 <= alls.length - 1) {
+                            if (BI.isNotNull(alls[index + 1]) && BI.isFunction(alls[index + 1].isSelected)
+                                && alls[index + 1].isSelected()) {
+                                alls[index + 1].setTopLineInVisible();
+                            }
+                        }
+                    }
+                }
+                self.fireEvent(BI.SelectDataLoader.EVENT_CHANGE);
+            }
+        })
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataLoader.superclass.setEnable.apply(this, arguments);
+        this.loader.setEnable(v)
+    },
+
+    doBehavior: function () {
+        this.loader.doBehavior.apply(this.loader, arguments);
+    },
+
+    populate: function () {
+        this.loader.populate.apply(this.loader, arguments);
+    },
+
+    getAllButtons: function(){
+        return this.loader.getAllButtons();
+    },
+
+    showView: function(b){
+        BI.each(this.loader.getAllButtons(),function(i, button){
+            button.showView && button.showView(b);
+        })
+    },
+
+    hideView: function(b){
+        BI.each(this.loader.getAllButtons(),function(i, button){
+            button.hideView && button.hideView(b);
+        })
+    },
+
+    setValue: function (v) {
+        this.loader.setValue(v);
+    },
+
+    getValue: function () {
+        return this.loader.getValue();
+    },
+
+    empty: function () {
+        this.loader.empty();
+    }
+});
+BI.SelectDataLoader.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_data_loader", BI.SelectDataLoader);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/node/node.level.js b/src/widget/selectdata/tree/node/node.level.js
new file mode 100644
index 000000000..94c726187
--- /dev/null
+++ b/src/widget/selectdata/tree/node/node.level.js
@@ -0,0 +1,111 @@
+/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectDataLevelNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevelNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevelNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level0-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 0,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        var title = this.options.title;
+        var warningTitle = this.options.warningTitle;
+        this.options.title = "";
+        this.options.warningTitle = "";
+        BI.SelectDataLevelNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            title: title,
+            warningTitle: warningTitle,
+            disabled: o.disabled,
+            py: o.py
+        });
+        this.tip = BI.createWidget({
+            type: "bi.label",
+            cls: "select-data-selected-count-label",
+            whiteSpace: "nowrap",
+            width: 25,
+            height: o.height
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }, {
+                width: 25,
+                el: this.tip
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevelNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevelNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevelNode.superclass.setValue.apply(this, arguments);
+        if (BI.isEmpty(items)) {
+            this.tip.setText("");
+        } else {
+            this.tip.setText("(" + items.length + ")");
+        }
+        this.tip.setTitle(items.toString());
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevelNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+        this.text.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level_node", BI.SelectDataLevelNode);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/node/node.level1.date.js b/src/widget/selectdata/tree/node/node.level1.date.js
new file mode 100644
index 000000000..f65c19c14
--- /dev/null
+++ b/src/widget/selectdata/tree/node/node.level1.date.js
@@ -0,0 +1,105 @@
+/**
+ * Created by GUY on 2015/9/15.
+ * @class BI.SelectDataLevel1DateNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevel1DateNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevel1DateNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level1-date-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 1,
+            open: false,
+            height: 25
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-group-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-group-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-group-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-group-font";
+            default:
+                return "select-data-field-date-group-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevel1DateNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget({
+            type: "bi.icon_text_item",
+            cls: this._getFieldClass(o.fieldType),
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height,
+            textLgap: 10,
+            textRgap: 5
+        });
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                el: this.button
+            }, {
+                el: this.checkbox,
+                width: 25
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevel1DateNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevel1DateNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevel1DateNode.superclass.setValue.apply(this, arguments);
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevel1DateNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level1_date_node", BI.SelectDataLevel1DateNode);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/node/node.level2.date.js b/src/widget/selectdata/tree/node/node.level2.date.js
new file mode 100644
index 000000000..5a83aa2d3
--- /dev/null
+++ b/src/widget/selectdata/tree/node/node.level2.date.js
@@ -0,0 +1,105 @@
+/**
+ * Created by GUY on 2015/9/15.
+ * @class BI.SelectDataLevel2DateNode
+ * @extends BI.NodeButton
+ */
+BI.SelectDataLevel2DateNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevel2DateNode.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level2-date-node bi-list-item",
+            id: "",
+            pId: "",
+            layer: 2,
+            open: false,
+            height: 25
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-group-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-group-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-group-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-group-font";
+            default:
+                return "select-data-field-date-group-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevel2DateNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.button = BI.createWidget({
+            type: "bi.icon_text_item",
+            cls: this._getFieldClass(o.fieldType),
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: o.height,
+            textLgap: 10,
+            textRgap: 5
+        });
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: o.layer * 20
+            }, {
+                el: this.button
+            }, {
+                el: this.checkbox,
+                width: 25
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doClick: function () {
+        BI.SelectDataLevel2DateNode.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SelectDataLevel2DateNode.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setValue: function (items) {
+        BI.SelectDataLevel2DateNode.superclass.setValue.apply(this, arguments);
+    },
+
+    setEnable: function (b) {
+        BI.SelectDataLevel2DateNode.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.select_data_level2_date_node", BI.SelectDataLevel2DateNode);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/tree.selectdata.js b/src/widget/selectdata/tree/tree.selectdata.js
new file mode 100644
index 000000000..93575d7e6
--- /dev/null
+++ b/src/widget/selectdata/tree/tree.selectdata.js
@@ -0,0 +1,91 @@
+/**
+ * 字段列表展开Expander
+ *
+ * Created by GUY on 2015/9/14.
+ * @class BI.SelectDataTree
+ * @extends BI.Widget
+ */
+BI.SelectDataTree = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-data-tree",
+            el: {},
+            expander: {},
+            items: [],
+            itemsCreator: BI.emptyFn
+        });
+    },
+
+    _init: function () {
+        BI.SelectDataTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tree = BI.createWidget({
+            type: "bi.custom_tree",
+            element: this,
+            expander: BI.extend({
+                type: "bi.select_data_expander",
+                el: {},
+                popup: {
+                    type: "bi.select_data_tree"
+                }
+            }, o.expander),
+            items: o.items,
+            itemsCreator: o.itemsCreator,
+
+            el: BI.extend({
+                type: "bi.select_data_loader"
+            }, o.el)
+        });
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.tree.on(BI.CustomTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectDataTree.EVENT_CHANGE, arguments);
+        })
+    },
+
+
+    setEnable: function (v) {
+        BI.SelectDataTree.superclass.setEnable.apply(this, arguments);
+        this.tree.setEnable(v)
+    },
+
+    showView: function(b){
+        BI.each(this.tree.getAllButtons(),function(i, button){
+            button.showView && button.showView(b);
+        })
+    },
+
+    hideView: function(b){
+        BI.each(this.tree.getAllButtons(),function(i, button){
+            button.hideView && button.hideView(b);
+        })
+    },
+
+    getAllButtons: function(){
+        return this.tree.getAllButtons();
+    },
+
+    doBehavior: function () {
+        this.tree.doBehavior.apply(this.tree, arguments);
+    },
+
+    empty: function () {
+
+    },
+
+    populate: function (items) {
+        this.tree.populate.apply(this.tree, arguments);
+    },
+
+    setValue: function (v) {
+        this.tree.setValue(v);
+    },
+
+    getValue: function () {
+        //这里需要去重,因为很有可能expander中保存了之前的value值
+        return BI.uniq(this.tree.getValue());
+    }
+});
+BI.SelectDataTree.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_data_tree", BI.SelectDataTree);
\ No newline at end of file
diff --git a/src/widget/selectdata/tree/treeitem/item.level.js b/src/widget/selectdata/tree/treeitem/item.level.js
new file mode 100644
index 000000000..e651339ea
--- /dev/null
+++ b/src/widget/selectdata/tree/treeitem/item.level.js
@@ -0,0 +1,154 @@
+/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectDataLevelItem
+ * @extends BI.Single
+ */
+BI.SelectDataLevelItem = BI.inherit(BI.Single, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectDataLevelItem.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-select-data-level0-item",
+            height: 25,
+            hgap: 0,
+            layer: 1,
+            fieldType: BICst.COLUMN.STRING,
+            lgap: 0,
+            rgap: 0
+        })
+    },
+
+    _getFieldClass: function (type) {
+        switch (type) {
+            case BICst.COLUMN.STRING:
+                return "select-data-field-string-font";
+            case BICst.COLUMN.NUMBER:
+                return "select-data-field-number-font";
+            case BICst.COLUMN.DATE:
+                return "select-data-field-date-font";
+            case BICst.COLUMN.COUNTER:
+                return "select-data-field-number-font";
+            default:
+                return "select-data-field-number-font";
+        }
+    },
+
+    _init: function () {
+        BI.SelectDataLevelItem.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button = BI.createWidget({
+            type: "bi.blank_icon_text_item",
+            trigger: "mousedown",
+            cls: "select-data-level0-item-button " + this._getFieldClass(o.fieldType),
+            blankWidth: o.layer * 20,
+            text: o.text,
+            value: o.value,
+            keyword: o.keyword,
+            height: 25,
+            textLgap: 10,
+            textRgap: 5
+        });
+        this.button.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.getValue(), self);
+        });
+
+        this.topLine = BI.createWidget({
+            type: "bi.layout",
+            height: 0,
+            cls: "select-data-top-line"
+        });
+        this.bottomLine = BI.createWidget({
+            type: "bi.layout",
+            height: 0,
+            cls: "select-data-bottom-line"
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.topLine,
+                top: 0,
+                left: o.lgap,
+                right: o.rgap
+            }, {
+                el: this.bottomLine,
+                bottom: 0,
+                left: o.lgap,
+                right: o.rgap
+            }, {
+                el: this.button,
+                top: 0,
+                left: o.lgap,
+                right: o.rgap
+            }]
+        });
+        this.topLine.invisible();
+        this.bottomLine.invisible();
+    },
+
+    setEnable: function (v) {
+        BI.SelectDataLevelItem.superclass.setEnable.apply(this, arguments)
+        this.button.setEnable(v);
+        try {
+            this.button.element.draggable(v ? "enable" : "disable");
+        } catch (e) {
+
+        }
+        if (!v) {
+            this.setSelected(false);
+        }
+    },
+
+    isSelected: function () {
+        return this.button.isSelected();
+    },
+
+    setSelected: function (b) {
+        this.button.setSelected(b);
+        if (!b) {
+            this.topLine.invisible();
+            this.bottomLine.invisible();
+            this.element.removeClass("select-data-item-top");
+            this.element.removeClass("select-data-item-bottom");
+        }
+    },
+
+    setTopLineVisible: function () {
+        this.topLine.visible();
+        this.element.addClass("select-data-item-top");
+    },
+
+    setTopLineInVisible: function () {
+        this.topLine.invisible();
+        this.element.removeClass("select-data-item-top");
+    },
+
+    setBottomLineVisible: function () {
+        this.bottomLine.visible();
+        this.element.addClass("select-data-item-bottom");
+    },
+
+    setBottomLineInVisible: function () {
+        this.bottomLine.invisible();
+        this.element.removeClass("select-data-item-bottom");
+    },
+
+    doRedMark: function () {
+        this.button.doRedMark.apply(this.button, arguments);
+    },
+
+    unRedMark: function () {
+        this.button.unRedMark.apply(this.button, arguments);
+    },
+
+    doHighLight: function () {
+        this.button.doHighLight.apply(this.button, arguments);
+    },
+
+    unHighLight: function () {
+        this.button.unHighLight.apply(this.button, arguments);
+    }
+});
+
+$.shortcut("bi.select_data_level_item", BI.SelectDataLevelItem);
\ No newline at end of file
diff --git a/src/widget/selecttree/nodes/node.first.plus.js b/src/widget/selecttree/nodes/node.first.plus.js
new file mode 100644
index 000000000..6b888734c
--- /dev/null
+++ b/src/widget/selecttree/nodes/node.first.plus.js
@@ -0,0 +1,85 @@
+/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeFirstPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-first-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.first_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_first_plus_group_node", BI.SelectTreeFirstPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/selecttree/nodes/node.last.plus.js b/src/widget/selecttree/nodes/node.last.plus.js
new file mode 100644
index 000000000..0168cae13
--- /dev/null
+++ b/src/widget/selecttree/nodes/node.last.plus.js
@@ -0,0 +1,85 @@
+/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeLastPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-last-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.last_tree_node_checkbox",
+            stopPropagation: true
+        })
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_last_plus_group_node", BI.SelectTreeLastPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/selecttree/nodes/node.mid.plus.js b/src/widget/selecttree/nodes/node.mid.plus.js
new file mode 100644
index 000000000..d5a010ab6
--- /dev/null
+++ b/src/widget/selecttree/nodes/node.mid.plus.js
@@ -0,0 +1,85 @@
+/**
+ * 加号表示的组节点
+ * Created by GUY on 2015/9/6.
+ * @class BI.SelectTreeMidPlusGroupNode
+ * @extends BI.NodeButton
+ */
+BI.SelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        var conf = BI.SelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-select-tree-mid-plus-group-node bi-list-item-active",
+            logic: {
+                dynamic: false
+            },
+            id: "",
+            pId: "",
+            readonly: true,
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.mid_tree_node_checkbox",
+            stopPropagation: true
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.triggerExpand();
+                } else {
+                    self.triggerCollapse();
+                }
+            }
+        });
+        var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left);
+        var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, {
+            width: 25,
+            el: this.checkbox
+        }, this.text);
+        BI.createWidget(BI.extend({
+            element: this
+        }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, {
+            items: items
+        }))));
+    },
+
+    isOnce: function () {
+        return true;
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.NodeButton.superclass.doClick.apply(this, arguments);
+    },
+
+    setOpened: function (v) {
+        BI.SelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments);
+        if (BI.isNotNull(this.checkbox)) {
+            this.checkbox.setSelected(v);
+        }
+    }
+});
+
+$.shortcut("bi.select_tree_mid_plus_group_node", BI.SelectTreeMidPlusGroupNode);
\ No newline at end of file
diff --git a/src/widget/selecttree/selecttree.combo.js b/src/widget/selecttree/selecttree.combo.js
new file mode 100644
index 000000000..010dd9c29
--- /dev/null
+++ b/src/widget/selecttree/selecttree.combo.js
@@ -0,0 +1,68 @@
+/**
+ * @class BI.SelectTreeCombo
+ * @extends BI.Widget
+ */
+BI.SelectTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-combo",
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SelectTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.select_tree_popup",
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    }
+});
+
+
+$.shortcut("bi.select_tree_combo", BI.SelectTreeCombo);
\ No newline at end of file
diff --git a/src/widget/selecttree/selecttree.expander.js b/src/widget/selecttree/selecttree.expander.js
new file mode 100644
index 000000000..8a8deac9c
--- /dev/null
+++ b/src/widget/selecttree/selecttree.expander.js
@@ -0,0 +1,73 @@
+/**
+ * @class BI.SelectTreeExpander
+ * @extends BI.Widget
+ */
+BI.SelectTreeExpander = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreeExpander.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-expander",
+            trigger: "click",
+            toggle: true,
+            direction: "bottom",
+            isDefaultInit: true,
+            el: {},
+            popup: {}
+        });
+    },
+
+    _init: function () {
+        BI.SelectTreeExpander.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget(BI.extend({stopPropagation: true}, o.el));
+        this.trigger.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                if (this.isSelected()) {
+                    self.expander.setValue([]);
+                }
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.expander = BI.createWidget({
+            type: "bi.expander",
+            element: this,
+            trigger: o.trigger,
+            toggle: o.toggle,
+            direction: o.direction,
+            isDefaultInit: o.isDefaultInit,
+            el: this.trigger,
+            popup: o.popup
+        });
+        this.expander.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.trigger.setSelected(false);
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        if (BI.contains(v, this.trigger.getValue())) {
+            this.trigger.setSelected(true);
+            this.expander.setValue([]);
+        } else {
+            this.trigger.setSelected(false);
+            this.expander.setValue(v);
+        }
+    },
+
+    getValue: function () {
+        if (this.trigger.isSelected()) {
+            return [this.trigger.getValue()];
+        }
+        return this.expander.getValue();
+    },
+
+    populate: function (items) {
+        this.expander.populate(items);
+    }
+});
+
+$.shortcut("bi.select_tree_expander", BI.SelectTreeExpander);
\ No newline at end of file
diff --git a/src/widget/selecttree/selecttree.popup.js b/src/widget/selecttree/selecttree.popup.js
new file mode 100644
index 000000000..deaeccefd
--- /dev/null
+++ b/src/widget/selecttree/selecttree.popup.js
@@ -0,0 +1,97 @@
+/**
+ * @class BI.SelectTreePopup
+ * @extends BI.Pane
+ */
+
+BI.SelectTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SelectTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-select-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            items: []
+        });
+    },
+
+    _formatItems: function (nodes, layer) {
+        var self = this;
+        BI.each(nodes, function (i, node) {
+            var extend = {layer: layer};
+            node.id = node.id || BI.UUID();
+            if (node.isParent === true || BI.isNotEmptyArray(node.children)) {
+                switch (i) {
+                    case 0 :
+                        extend.type = "bi.select_tree_first_plus_group_node";
+                        break;
+                    case nodes.length - 1 :
+                        extend.type = "bi.select_tree_last_plus_group_node";
+                        break;
+                    default :
+                        extend.type = "bi.select_tree_mid_plus_group_node";
+                        break;
+                }
+                BI.defaults(node, extend);
+                self._formatItems(node.children);
+            } else {
+                switch (i) {
+                    case nodes.length - 1:
+                        extend.type = "bi.last_tree_leaf_item";
+                        break;
+                    default :
+                        extend.type = "bi.mid_tree_leaf_item";
+                }
+                BI.defaults(node, extend);
+            }
+        });
+        return nodes;
+    },
+
+    _init: function () {
+        BI.SelectTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.level_tree',
+            expander: {
+                type: "bi.select_tree_expander",
+                isDefaultInit: true
+            },
+            items: this._formatItems(BI.Tree.transformToTreeFormat(o.items)),
+            chooseType: BI.Selection.Single
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SelectTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.SelectTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.SelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.select_tree_popup", BI.SelectTreePopup);
\ No newline at end of file
diff --git a/src/widget/sequencetable/dynamicnumber.sequencetable.js b/src/widget/sequencetable/dynamicnumber.sequencetable.js
new file mode 100644
index 000000000..8ed0740c0
--- /dev/null
+++ b/src/widget/sequencetable/dynamicnumber.sequencetable.js
@@ -0,0 +1,71 @@
+/**
+ *
+ * Created by GUY on 2016/8/10.
+ * @class BI.SequenceTableDynamicNumber
+ * @extends BI.SequenceTableTreeNumber
+ */
+BI.SequenceTableDynamicNumber = BI.inherit(BI.SequenceTableTreeNumber, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableDynamicNumber.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-sequence-table-dynamic-number"
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableDynamicNumber.superclass._init.apply(this, arguments);
+    },
+
+    _formatNumber: function (nodes) {
+        var self = this, o = this.options;
+        var result = [];
+        var count = this._getStart(nodes);
+
+        function getLeafCount(node) {
+            var cnt = 0;
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    cnt += getLeafCount(child);
+                });
+                if (node.children.length > 1 && BI.isNotEmptyArray(node.values)) {
+                    cnt++;
+                }
+            } else {
+                cnt++;
+            }
+            return cnt;
+        }
+
+        var start = 0, top = 0;
+        BI.each(nodes, function (i, node) {
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    var cnt = getLeafCount(child);
+                    result.push({
+                        text: count++,
+                        start: start,
+                        top: top,
+                        cnt: cnt,
+                        index: index,
+                        height: cnt * o.rowSize
+                    });
+                    start += cnt;
+                    top += cnt * o.rowSize;
+                });
+                if (BI.isNotEmptyArray(node.values)) {
+                    result.push({
+                        text: BI.i18nText("BI-Summary_Values"),
+                        start: start++,
+                        top: top,
+                        cnt: 1,
+                        isSummary: true,
+                        height: o.rowSize
+                    });
+                    top += o.rowSize;
+                }
+            }
+        });
+        return result;
+    }
+});
+$.shortcut('bi.sequence_table_dynamic_number', BI.SequenceTableDynamicNumber);
\ No newline at end of file
diff --git a/src/widget/sequencetable/listnumber.sequencetable.js b/src/widget/sequencetable/listnumber.sequencetable.js
new file mode 100644
index 000000000..f2371ddff
--- /dev/null
+++ b/src/widget/sequencetable/listnumber.sequencetable.js
@@ -0,0 +1,206 @@
+/**
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTableListNumber
+ * @extends BI.Widget
+ */
+BI.SequenceTableListNumber = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableListNumber.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table-list-number",
+            isNeedFreeze: false,
+            scrollTop: 0,
+            startSequence: 1,//开始的序号
+            headerRowSize: 25,
+            rowSize: 25,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: [],
+
+            pageSize: 20
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableListNumber.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.start = o.startSequence;
+        this.renderedCells = [];
+        this.renderedKeys = [];
+
+        this.header = BI.createWidget({
+            type: "bi.table_style_cell",
+            cls: "sequence-table-title-cell",
+            styleGetter: o.headerCellStyleGetter,
+            text: BI.i18nText("BI-Number_Index")
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            width: 60,
+            scrollable: false
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.container]
+        });
+
+        this.layout = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.header,
+                height: o.headerRowSize * o.header.length
+            }, {
+                el: this.scrollContainer
+            }]
+        });
+        this._populate();
+    },
+
+    _layout: function () {
+        var self = this, o = this.options;
+        var headerHeight = o.headerRowSize * o.header.length;
+        var items = this.layout.attr("items");
+        if (o.isNeedFreeze === false) {
+            items[0].height = 0;
+        } else if (o.isNeedFreeze === true) {
+            items[0].height = headerHeight;
+        }
+        this.layout.attr("items", items);
+        this.layout.resize();
+        this.container.setHeight(o.items.length * o.rowSize);
+        this.scrollContainer.element.scrollTop(o.scrollTop);
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+        var scrollTop = BI.clamp(o.scrollTop, 0, o.rowSize * o.items.length - (o.height - o.header.length * o.headerRowSize) + BI.DOM.getScrollWidth());
+        var start = Math.floor(scrollTop / o.rowSize);
+        var end = start + Math.floor((o.height - o.header.length * o.headerRowSize) / o.rowSize);
+        var renderedCells = [], renderedKeys = [];
+        for (var i = start, cnt = 0; i <= end && i < o.items.length; i++, cnt++) {
+            var index = BI.deepIndexOf(this.renderedKeys, this.start + i);
+            var top = i * o.rowSize;
+            if (index > -1) {
+                if (o.rowSize !== this.renderedCells[index]._height) {
+                    this.renderedCells[index]._height = o.rowSize;
+                    this.renderedCells[index].el.setHeight(o.rowSize);
+                }
+                if (this.renderedCells[index].top !== top) {
+                    this.renderedCells[index].top = top;
+                    this.renderedCells[index].el.element.css("top", top + "px");
+                }
+                renderedCells.push(this.renderedCells[index]);
+            } else {
+                var child = BI.createWidget(BI.extend({
+                    type: "bi.table_style_cell",
+                    cls: "sequence-table-number-cell",
+                    width: 60,
+                    height: o.rowSize,
+                    text: this.start + i,
+                    styleGetter: function (index) {
+                        return function () {
+                            return o.sequenceCellStyleGetter(self.start + i - 1);
+                        }
+                    }(cnt)
+                }));
+                renderedCells.push({
+                    el: child,
+                    left: 0,
+                    top: top,
+                    _height: o.rowSize
+                });
+            }
+            renderedKeys.push(this.start + i);
+        }
+
+        //已存在的, 需要添加的和需要删除的
+        var existSet = {}, addSet = {}, deleteArray = [];
+        BI.each(renderedKeys, function (i, key) {
+            if (BI.deepContains(self.renderedKeys, key)) {
+                existSet[i] = key;
+            } else {
+                addSet[i] = key;
+            }
+        });
+        BI.each(this.renderedKeys, function (i, key) {
+            if (BI.deepContains(existSet, key)) {
+                return;
+            }
+            if (BI.deepContains(addSet, key)) {
+                return;
+            }
+            deleteArray.push(i);
+        });
+        BI.each(deleteArray, function (i, index) {
+            self.renderedCells[index].el.destroy();
+        });
+        var addedItems = [];
+        BI.each(addSet, function (index) {
+            addedItems.push(renderedCells[index])
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: addedItems
+        });
+        this.renderedCells = renderedCells;
+        this.renderedKeys = renderedKeys;
+    },
+
+    _populate: function () {
+        this.header.populate();
+        this._layout();
+        this._calculateChildrenToRender();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        if (this.options.scrollTop !== scrollTop) {
+            this.options.scrollTop = scrollTop;
+            this.scrollContainer.element.scrollTop(scrollTop);
+        }
+    },
+
+    getVerticalScroll: function () {
+        return this.options.scrollTop;
+    },
+
+    setVPage: function (v) {
+        var o = this.options;
+        this.start = (v - 1) * o.pageSize + 1;
+    },
+
+    _restore: function () {
+        var o = this.options;
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+    },
+
+    restore: function () {
+        this._restore();
+    },
+
+    populate: function (items, header) {
+        var o = this.options;
+        if (items && items !== this.options.items) {
+            o.items = items;
+            this._restore();
+        }
+        if (header && header !== this.options.header) {
+            o.header = header;
+        }
+        this._populate();
+    }
+});
+$.shortcut('bi.sequence_table_list_number', BI.SequenceTableListNumber);
\ No newline at end of file
diff --git a/src/widget/sequencetable/sequencetable.js b/src/widget/sequencetable/sequencetable.js
new file mode 100644
index 000000000..9f120ac48
--- /dev/null
+++ b/src/widget/sequencetable/sequencetable.js
@@ -0,0 +1,251 @@
+/**
+ * 带有序号的表格
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTable
+ * @extends BI.Widget
+ */
+BI.SequenceTable = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table",
+            el: {
+                type: "bi.adaptive_table"
+            },
+
+            sequence: {},
+
+            isNeedResize: true,
+            isResizeAdapt: false,
+
+            isNeedFreeze: false,//是否需要冻结单元格
+            freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效
+
+            isNeedMerge: false,//是否需要合并单元格
+            mergeCols: [], //合并的单元格列号
+            mergeRule: BI.emptyFn,
+
+            columnSize: [],
+            minColumnSize: [],
+            maxColumnSize: [],
+            headerRowSize: 25,
+            rowSize: 25,
+
+            regionColumnSize: [],
+
+            headerCellStyleGetter: BI.emptyFn,
+            summaryCellStyleGetter: BI.emptyFn,
+            sequenceCellStyleGetter: BI.emptyFn,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: [],
+
+            showSequence: false,
+            startSequence: 1//开始的序号
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.sequence = BI.createWidget(o.sequence, {
+            type: "bi.sequence_table_list_number",
+            invisible: o.showSequence === false,
+            startSequence: o.startSequence,
+            isNeedFreeze: o.isNeedFreeze,
+            header: o.header,
+            items: o.items,
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+            width: 60,
+            height: o.height - BI.GridTableScrollbar.SIZE,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter
+        });
+        this.table = BI.createWidget(o.el, {
+            type: "bi.adaptive_table",
+            width: o.showSequence === true ? o.width - 60 : o.width,
+            height: o.height,
+            isNeedResize: o.isNeedResize,
+            isResizeAdapt: o.isResizeAdapt,
+
+            isNeedFreeze: o.isNeedFreeze,
+            freezeCols: o.freezeCols,
+
+            isNeedMerge: o.isNeedMerge,
+            mergeCols: o.mergeCols,
+            mergeRule: o.mergeRule,
+
+            columnSize: o.columnSize,
+            minColumnSize: o.minColumnSize,
+            maxColumnSize: o.maxColumnSize,
+            headerRowSize: o.headerRowSize,
+            rowSize: o.rowSize,
+
+            regionColumnSize: o.regionColumnSize,
+
+            headerCellStyleGetter: o.headerCellStyleGetter,
+            summaryCellStyleGetter: o.summaryCellStyleGetter,
+            sequenceCellStyleGetter: o.sequenceCellStyleGetter,
+
+            header: o.header,
+            items: o.items,
+            //交叉表头
+            crossHeader: o.crossHeader,
+            crossItems: o.crossItems
+        });
+
+        this.table.on(BI.Table.EVENT_TABLE_SCROLL, function (scroll) {
+            if (self.sequence.getVerticalScroll() !== this.getVerticalScroll()) {
+                self.sequence.setVerticalScroll(this.getVerticalScroll());
+                self.sequence.populate();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () {
+            o.regionColumnSize = this.getRegionColumnSize();
+            o.columnSize = this.getColumnSize();
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments);
+        });
+
+        this.htape = BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.sequence,
+                left: 0,
+                top: 0
+            }, {
+                el: this.table,
+                top: 0,
+                left: o.showSequence === true ? 60 : 0
+            }]
+        });
+        this._populate();
+    },
+
+    _populate: function () {
+        var o = this.options;
+        this.sequence.attr({
+            items: o.items,
+            header: o.header,
+            crossItems: o.crossItems,
+            crossHeader: o.crossHeader
+        });
+        if (o.showSequence === true) {
+            this.sequence.setVisible(true);
+            this.table.element.css("left", "60px");
+            this.table.setWidth(o.width - 60);
+        } else {
+            this.sequence.setVisible(false);
+            this.table.element.css("left", "0px");
+            this.table.setWidth(o.width);
+        }
+    },
+
+    setWidth: function (width) {
+        BI.PageTable.superclass.setWidth.apply(this, arguments);
+        this.table.setWidth(this.options.showSequence ? width - 60 : width);
+    },
+
+    setHeight: function (height) {
+        BI.PageTable.superclass.setHeight.apply(this, arguments);
+        this.table.setHeight(height);
+        this.sequence.setHeight(height - BI.GridTableScrollbar.SIZE);
+    },
+
+    setColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setColumnSize(columnSize);
+    },
+
+    getColumnSize: function () {
+        return this.table.getColumnSize();
+    },
+
+    setRegionColumnSize: function (columnSize) {
+        this.options.columnSize = columnSize;
+        this.table.setRegionColumnSize(columnSize);
+    },
+
+    getRegionColumnSize: function () {
+        return this.table.getRegionColumnSize();
+    },
+
+    hasLeftHorizontalScroll: function () {
+        return this.table.hasLeftHorizontalScroll();
+    },
+
+    hasRightHorizontalScroll: function () {
+        return this.table.hasRightHorizontalScroll();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        this.table.setVerticalScroll(scrollTop);
+        this.sequence.setVerticalScroll(scrollTop);
+    },
+
+    getVerticalScroll: function () {
+        return this.table.getVerticalScroll();
+    },
+
+    setVPage: function (page) {
+        this.sequence.setVPage && this.sequence.setVPage(page);
+    },
+
+    setHPage: function (page) {
+        this.sequence.setHPage && this.sequence.setHPage(page);
+    },
+
+    attr: function () {
+        BI.SequenceTable.superclass.attr.apply(this, arguments);
+        this.table.attr.apply(this.table, arguments);
+        this.sequence.attr.apply(this.sequence, arguments);
+    },
+
+    restore: function () {
+        this.table.restore();
+        this.sequence.restore();
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        if (items) {
+            o.items = items;
+        }
+        if (header) {
+            o.header = header;
+        }
+        if (crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        this._populate();
+        this.table.populate.apply(this.table, arguments);
+        this.sequence.populate.apply(this.sequence, arguments);
+        this.sequence.setVerticalScroll(this.table.getVerticalScroll());
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.SequenceTable.superclass.destroy.apply(this, arguments);
+    }
+});
+$.shortcut('bi.sequence_table', BI.SequenceTable);
\ No newline at end of file
diff --git a/src/widget/sequencetable/treenumber.sequencetable.js b/src/widget/sequencetable/treenumber.sequencetable.js
new file mode 100644
index 000000000..acadf84da
--- /dev/null
+++ b/src/widget/sequencetable/treenumber.sequencetable.js
@@ -0,0 +1,383 @@
+/**
+ *
+ * Created by GUY on 2016/5/26.
+ * @class BI.SequenceTableTreeNumber
+ * @extends BI.Widget
+ */
+BI.SequenceTableTreeNumber = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SequenceTableTreeNumber.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sequence-table-tree-number",
+            isNeedFreeze: false,
+            startSequence: 1,//开始的序号
+            scrollTop: 0,
+            headerRowSize: 25,
+            rowSize: 25,
+
+            header: [],
+            items: [], //二维数组
+
+            //交叉表头
+            crossHeader: [],
+            crossItems: []
+        });
+    },
+
+    _init: function () {
+        BI.SequenceTableTreeNumber.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.vCurr = 1;
+        this.hCurr = 1;
+        this.tasks = [];
+        this.renderedCells = [];
+        this.renderedKeys = [];
+
+        this.header = BI.createWidget({
+            type: "bi.table_style_cell",
+            cls: "sequence-table-title-cell",
+            styleGetter: o.headerCellStyleGetter,
+            text: BI.i18nText("BI-Number_Index")
+        });
+        this.container = BI.createWidget({
+            type: "bi.absolute",
+            width: 60,
+            scrollable: false
+        });
+
+        this.scrollContainer = BI.createWidget({
+            type: "bi.vertical",
+            scrollable: false,
+            scrolly: false,
+            items: [this.container]
+        });
+
+        this.layout = BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.header,
+                height: this._getHeaderHeight()
+            }, {
+                el: this.scrollContainer
+            }]
+        });
+        //缓存第一行对应的序号
+        this.start = this.options.startSequence;
+        this.cache = {};
+        this._nextState();
+
+        this._populate();
+    },
+
+    _getNextSequence: function (nodes) {
+        var self = this;
+        var start = this.start;
+        var cnt = this.start;
+
+        function track(node) {
+            self.cache[node.text || node.value] = cnt++;
+        }
+
+        BI.each(nodes, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    if (index === 0) {
+                        if (self.cache[child.text || child.value]) {
+                            start = cnt = self.cache[child.text || child.value];
+                        }
+                    }
+                    track(child)
+                });
+            }
+        });
+        this.start = cnt;
+        return start;
+    },
+
+    _getStart: function (nodes) {
+        var self = this;
+        var start = this.start;
+        BI.each(nodes, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    if (index === 0) {
+                        if (self.cache[child.text || child.value]) {
+                            start = self.cache[child.text || child.value];
+                        }
+                    }
+                });
+            }
+        });
+        return start;
+    },
+
+    _formatNumber: function (nodes) {
+        var self = this, o = this.options;
+        var result = [];
+        var count = this._getStart(nodes);
+
+        function getLeafCount(node) {
+            var cnt = 0;
+            if (BI.isNotEmptyArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    cnt += getLeafCount(child);
+                });
+                if (/**node.children.length > 1 && **/BI.isNotEmptyArray(node.values)) {
+                    cnt++;
+                }
+            } else {
+                cnt++;
+            }
+            return cnt;
+        }
+
+        var start = 0, top = 0;
+        BI.each(nodes, function (i, node) {
+            if (BI.isArray(node.children)) {
+                BI.each(node.children, function (index, child) {
+                    var cnt = getLeafCount(child);
+                    result.push({
+                        text: count++,
+                        start: start,
+                        top: top,
+                        cnt: cnt,
+                        index: index,
+                        height: cnt * o.rowSize
+                    });
+                    start += cnt;
+                    top += cnt * o.rowSize;
+                });
+                if (BI.isNotEmptyArray(node.values)) {
+                    result.push({
+                        text: BI.i18nText("BI-Summary_Values"),
+                        start: start++,
+                        top: top,
+                        cnt: 1,
+                        isSummary: true,
+                        height: o.rowSize
+                    });
+                    top += o.rowSize;
+                }
+            }
+        });
+        return result;
+    },
+
+    _layout: function () {
+        var self = this, o = this.options;
+        var headerHeight = this._getHeaderHeight();
+        var items = this.layout.attr("items");
+        if (o.isNeedFreeze === false) {
+            items[0].height = 0;
+        } else if (o.isNeedFreeze === true) {
+            items[0].height = headerHeight;
+        }
+        this.layout.attr("items", items);
+        this.layout.resize();
+        this.scrollContainer.element.scrollTop(o.scrollTop);
+    },
+
+    _getHeaderHeight: function () {
+        var o = this.options;
+        return o.headerRowSize * (o.crossHeader.length + (o.header.length > 0 ? 1 : 0));
+    },
+
+    _nextState: function () {
+        var o = this.options;
+        this._getNextSequence(o.items);
+    },
+
+    _prevState: function () {
+        var self = this, o = this.options;
+        var firstChild;
+        BI.some(o.items, function (i, node) {
+            if (BI.isNotEmptyArray(node.children)) {
+                return BI.some(node.children, function (j, child) {
+                    firstChild = child;
+                    return true;
+                });
+            }
+        });
+        if (firstChild && BI.isNotEmptyObject(this.cache)) {
+            this.start = this.cache[firstChild.text || firstChild.value];
+        } else {
+            this.start = 1;
+        }
+        this._nextState();
+    },
+
+    _getMaxScrollTop: function (numbers) {
+        var cnt = 0;
+        BI.each(numbers, function (i, number) {
+            cnt += number.cnt;
+        });
+        return Math.max(0, cnt * this.options.rowSize - (this.options.height - this._getHeaderHeight()) + BI.DOM.getScrollWidth());
+    },
+
+    _calculateChildrenToRender: function () {
+        var self = this, o = this.options;
+
+        var renderedCells = [], renderedKeys = [];
+        var numbers = this._formatNumber(o.items);
+        var intervalTree = BI.PrefixIntervalTree.uniform(numbers.length, 0);
+        BI.each(numbers, function (i, number) {
+            intervalTree.set(i, number.height);
+        });
+        var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop(numbers));
+        var index = intervalTree.greatestLowerBound(scrollTop);
+        var offsetTop = -(scrollTop - (index > 0 ? intervalTree.sumTo(index - 1) : 0));
+        var height = offsetTop;
+        var bodyHeight = o.height - this._getHeaderHeight();
+        while (height < bodyHeight && index < numbers.length) {
+            renderedKeys.push(index);
+            offsetTop += numbers[index].height;
+            height += numbers[index].height;
+            index++;
+        }
+
+        BI.each(renderedKeys, function (i, key) {
+            var index = BI.deepIndexOf(self.renderedKeys, key);
+            if (index > -1) {
+                if (numbers[key].height !== self.renderedCells[index]._height) {
+                    self.renderedCells[index]._height = numbers[key].height;
+                    self.renderedCells[index].el.setHeight(numbers[key].height);
+                }
+                if (numbers[key].top !== self.renderedCells[index].top) {
+                    self.renderedCells[index].top = numbers[key].top;
+                    self.renderedCells[index].el.element.css("top", numbers[key].top + "px");
+                }
+                renderedCells.push(self.renderedCells[index]);
+            } else {
+                var child = BI.createWidget(BI.extend({
+                    type: "bi.table_style_cell",
+                    cls: "sequence-table-number-cell",
+                    width: 60,
+                    styleGetter: numbers[key].isSummary === true ? function () {
+                        return o.summaryCellStyleGetter(true);
+                    } : function (key) {
+                        return function () {
+                            return o.sequenceCellStyleGetter(key);
+                        }
+                    }(numbers[key].index)
+                }, numbers[key]));
+                renderedCells.push({
+                    el: child,
+                    left: 0,
+                    top: numbers[key].top,
+                    _height: numbers[key].height
+                });
+            }
+        });
+
+        //已存在的, 需要添加的和需要删除的
+        var existSet = {}, addSet = {}, deleteArray = [];
+        BI.each(renderedKeys, function (i, key) {
+            if (BI.deepContains(self.renderedKeys, key)) {
+                existSet[i] = key;
+            } else {
+                addSet[i] = key;
+            }
+        });
+        BI.each(this.renderedKeys, function (i, key) {
+            if (BI.deepContains(existSet, key)) {
+                return;
+            }
+            if (BI.deepContains(addSet, key)) {
+                return;
+            }
+            deleteArray.push(i);
+        });
+        BI.each(deleteArray, function (i, index) {
+            self.renderedCells[index].el.destroy();
+        });
+        var addedItems = [];
+        BI.each(addSet, function (index) {
+            addedItems.push(renderedCells[index])
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.container,
+            items: addedItems
+        });
+        this.renderedCells = renderedCells;
+        this.renderedKeys = renderedKeys;
+
+        this.container.setHeight(intervalTree.sumUntil(numbers.length));
+    },
+
+    _restore: function () {
+        BI.each(this.renderedCells, function (i, cell) {
+            cell.el.destroy();
+        });
+        this.renderedCells = [];
+        this.renderedKeys = [];
+    },
+
+    _populate: function () {
+        var self = this;
+        BI.each(this.tasks, function (i, task) {
+            task.apply(self);
+        });
+        this.tasks = [];
+        this.header.populate();
+        this._layout();
+        this._calculateChildrenToRender();
+    },
+
+    setVerticalScroll: function (scrollTop) {
+        if (this.options.scrollTop !== scrollTop) {
+            this.options.scrollTop = scrollTop;
+            this.scrollContainer.element.scrollTop(scrollTop);
+        }
+    },
+
+    getVerticalScroll: function () {
+        return this.options.scrollTop;
+    },
+
+    setVPage: function (v) {
+        if (v <= 1) {
+            this.cache = {};
+            this.start = this.options.startSequence;
+            this._restore();
+            this.tasks.push(this._nextState);
+        } else if (v === this.vCurr + 1) {
+            this.tasks.push(this._nextState);
+        } else if (v === this.vCurr - 1) {
+            this.tasks.push(this._prevState);
+        }
+        this.vCurr = v;
+    },
+
+    setHPage: function (v) {
+        if (v !== this.hCurr) {
+            this.tasks.push(this._prevState);
+        }
+        this.hCurr = v;
+    },
+
+    restore: function () {
+        this._restore();
+    },
+
+    populate: function (items, header, crossItems, crossHeader) {
+        var o = this.options;
+        if (items && items !== this.options.items) {
+            o.items = items;
+            this._restore();
+            this.tasks.push(this._prevState);
+        }
+        if (header && header !== this.options.header) {
+            o.header = header;
+        }
+        if (crossItems && crossItems !== this.options.crossItems) {
+            o.crossItems = crossItems;
+        }
+        if (crossHeader && crossHeader !== this.options.crossHeader) {
+            o.crossHeader = crossHeader;
+        }
+        this._populate();
+    }
+});
+$.shortcut('bi.sequence_table_tree_number', BI.SequenceTableTreeNumber);
\ No newline at end of file
diff --git a/src/widget/simplesearcher/searcher.simple.js b/src/widget/simplesearcher/searcher.simple.js
new file mode 100644
index 000000000..a674174f6
--- /dev/null
+++ b/src/widget/simplesearcher/searcher.simple.js
@@ -0,0 +1,108 @@
+/**
+ * 简单的搜索功能
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSearcher
+ * @extends BI.Widget
+ */
+BI.SimpleSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-simple-searcher",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+
+        this.tree = BI.createWidget({
+            type: "bi.select_data_tree",
+            items: o.items,
+            el: {
+                el: {
+                    chooseType: o.chooseType
+                }
+            },
+            itemsCreator: o.itemsCreator
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSearcher.EVENT_CHANGE, arguments);
+        });
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(op, function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            popup: {
+                matcher: {
+                    type: "bi.select_data_tree",
+                    el: {
+                        el: {
+                            chooseType: o.chooseType
+                        }
+                    },
+                    itemsCreator: o.itemsCreator
+                },
+                searcher: {
+                    type: "bi.select_data_tree",
+                    el: {
+                        el: {
+                            chooseType: o.chooseType
+                        }
+                    },
+                    itemsCreator: o.itemsCreator
+                }
+            },
+            adapter: this.tree
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.tree]
+        })
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    }
+});
+BI.SimpleSearcher.EVENT_CHANGE = "SimpleSearcher.EVENT_CHANGE";
+$.shortcut('bi.simple_searcher', BI.SimpleSearcher);
\ No newline at end of file
diff --git a/src/widget/simpleselectdata/searcher/searcher.simpleselectdata.js b/src/widget/simpleselectdata/searcher/searcher.simpleselectdata.js
new file mode 100644
index 000000000..30a3d3b58
--- /dev/null
+++ b/src/widget/simpleselectdata/searcher/searcher.simpleselectdata.js
@@ -0,0 +1,104 @@
+/**
+ * 完成搜索功能模块
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearcher
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearcher = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearcher.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-simple-select-data-searcher",
+            items: [],
+            itemsCreator: BI.emptyFn,
+            popup: {},
+            adapter: {}
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearcher.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+
+        this.tree = BI.createWidget(o.adapter, {
+            type: "bi.select_data_tree",
+            items: o.items,
+            el: {
+                el: {
+                    chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE
+                }
+            },
+            itemsCreator: o.itemsCreator
+        });
+        this.tree.on(BI.SelectDataTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+        this.searcherPane = BI.createWidget(o.popup, {
+            type: "bi.simple_select_data_search_result_pane",
+            itemsCreator: o.itemsCreator
+        });
+        this.searcherPane.on(BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE, function () {
+            self.searcher.doSearch();
+        });
+        this.searcherPane.on(BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM, arguments);
+        });
+
+
+        this.searcher = BI.createWidget({
+            type: "bi.searcher",
+            el: {
+                type: "bi.small_search_editor"
+            },
+            isAutoSearch: false, //是否自动搜索
+            isAutoSync: false,
+            onSearch: function (op, populate) {
+                o.itemsCreator(BI.extend(op, {
+                    searchType: self.searcherPane.getSegmentValue()
+                }), function (searchResult, matchResult) {
+                    populate(searchResult, matchResult, op.keyword);
+                })
+            },
+            chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE,
+            popup: this.searcherPane,
+            adapter: this.tree
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.absolute",
+                    items: [{
+                        el: this.searcher,
+                        left: 10,
+                        right: 10,
+                        top: 10
+                    }]
+                },
+                height: 45
+            }, this.tree]
+        })
+    },
+
+    stopSearch: function () {
+        this.searcher.stopSearch();
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getValue: function () {
+        return this.searcher.getValue();
+    },
+
+    populate: function () {
+        this.tree.populate.apply(this.tree, arguments);
+    }
+});
+BI.SimpleSelectDataSearcher.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM";
+$.shortcut('bi.simple_select_data_searcher', BI.SimpleSelectDataSearcher);
\ No newline at end of file
diff --git a/src/widget/simpleselectdata/searchpane/result.search.simpleselectdata.js b/src/widget/simpleselectdata/searchpane/result.search.simpleselectdata.js
new file mode 100644
index 000000000..49d25e338
--- /dev/null
+++ b/src/widget/simpleselectdata/searchpane/result.search.simpleselectdata.js
@@ -0,0 +1,104 @@
+/**
+ * 搜索结果面板
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearchResultPane
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearchResultPane = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearchResultPane.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-select-data-search-result-pane bi-select-data-search-result-pane bi-searcher-view",
+            itemsCreator: BI.emptyFn,
+            segment: {}
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearchResultPane.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.segment = BI.createWidget(o.segment, {
+            type: "bi.simple_select_data_search_segment",
+            cls: "search-result-toolbar"
+        });
+        this.segment.on(BI.SimpleSelectDataSearchSegment.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE);
+        });
+
+        this.resultPane = BI.createWidget({
+            type: "bi.searcher_view",
+            matcher: {
+                type: "bi.select_data_tree",
+                el: {
+                    el: {
+                        chooseType: BI.Selection.Single
+                    }
+                },
+                itemsCreator: o.itemsCreator
+            },
+            searcher: {
+                type: "bi.select_data_tree",
+                el: {
+                    el: {
+                        chooseType: BI.Selection.Single
+                    }
+                },
+                itemsCreator: o.itemsCreator
+            }
+        });
+
+        this.resultPane.on(BI.SearcherView.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.vtape",
+            element: this,
+            items: [{
+                el: this.segment,
+                height: 30
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 2
+            }, {
+                type: "bi.border",
+                cls: "search-result-line",
+                height: 1
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: this.resultPane,
+                    left: 0,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+    },
+
+    empty: function () {
+        this.resultPane.empty();
+    },
+
+    populate: function (searchResult, matchResult, keyword) {
+        this.resultPane.populate.apply(this.resultPane, arguments);
+    },
+
+    setValue: function (v) {
+
+    },
+
+    getSegmentValue: function () {
+        return this.segment.getValue();
+    },
+
+    getValue: function () {
+        return this.resultPane.getValue();
+    }
+});
+BI.SimpleSelectDataSearchResultPane.EVENT_SEARCH_TYPE_CHANGE = "EVENT_SEARCH_TYPE_CHANGE";
+BI.SimpleSelectDataSearchResultPane.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.simple_select_data_search_result_pane', BI.SimpleSelectDataSearchResultPane);
\ No newline at end of file
diff --git a/src/widget/simpleselectdata/searchpane/segment.search.simpleselectdata.js b/src/widget/simpleselectdata/searchpane/segment.search.simpleselectdata.js
new file mode 100644
index 000000000..817a42a4b
--- /dev/null
+++ b/src/widget/simpleselectdata/searchpane/segment.search.simpleselectdata.js
@@ -0,0 +1,69 @@
+/**
+ * search面板选项栏
+ *
+ * Created by GUY on 2015/9/16.
+ * @class BI.SimpleSelectDataSearchSegment
+ * @extends BI.Widget
+ */
+BI.SimpleSelectDataSearchSegment = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataSearchSegment.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-select-data-search-segment",
+            height: 30,
+            items: [{
+                text: BI.i18nText("BI-Basic_Field"),
+                selected: true,
+                value: BI.SelectDataSearchSegment.SECTION_FIELD
+            }, {
+                text: BI.i18nText("BI-Basic_Table"),
+                value: BI.SelectDataSearchSegment.SECTION_TABLE
+            }]
+        });
+    },
+
+    _init: function () {
+        BI.SimpleSelectDataSearchSegment.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.segment = BI.createWidget({
+            type: "bi.segment",
+            height: 20,
+            cls: "search-segment-field-table",
+            items: o.items
+        });
+        this.segment.on(BI.Segment.EVENT_CHANGE, function(){
+            self.fireEvent(BI.SimpleSelectDataSearchSegment.EVENT_CHANGE);
+        });
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [{
+                type: "bi.absolute",
+                height: o.height,
+                items: [{
+                    el: this.segment,
+                    top: 5,
+                    right: 10,
+                    left: 10,
+                    bottom: 5
+                }]
+            }]
+        });
+    },
+
+    setValue: function (v) {
+        var self = this;
+        BI.each([BI.SelectDataSearchSegment.SECTION_FIELD,
+            BI.SelectDataSearchSegment.SECTION_TABLE], function (i, key) {
+            if (key & v) {
+                self.segment.setValue(key & v);
+            }
+        });
+    },
+
+    getValue: function () {
+        return this.segment.getValue()[0]
+    }
+});
+
+BI.SimpleSelectDataSearchSegment.EVENT_CHANGE = "SimpleSelectDataSearchSegment.EVENT_CHANGE";
+$.shortcut('bi.simple_select_data_search_segment', BI.SimpleSelectDataSearchSegment);
\ No newline at end of file
diff --git a/src/widget/simpleselectdata/treenode/node.level0.js b/src/widget/simpleselectdata/treenode/node.level0.js
new file mode 100644
index 000000000..3c5e85147
--- /dev/null
+++ b/src/widget/simpleselectdata/treenode/node.level0.js
@@ -0,0 +1,76 @@
+/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SimpleSelectDataLevel0Node
+ * @extends BI.NodeButton
+ */
+BI.SimpleSelectDataLevel0Node = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataLevel0Node.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-simple-select-data-level0-node bi-list-item",
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SimpleSelectDataLevel0Node.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if (type === BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SimpleSelectDataLevel0Node.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SimpleSelectDataLevel0Node.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setEnable: function (b) {
+        BI.SimpleSelectDataLevel0Node.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.simple_select_data_level0_node", BI.SimpleSelectDataLevel0Node);
\ No newline at end of file
diff --git a/src/widget/simpleselectdata/treenode/node.level1.js b/src/widget/simpleselectdata/treenode/node.level1.js
new file mode 100644
index 000000000..863ca719b
--- /dev/null
+++ b/src/widget/simpleselectdata/treenode/node.level1.js
@@ -0,0 +1,81 @@
+/**
+ * Created by GUY on 2015/9/6.
+ * @class BI.SimpleSelectDataLevel1Node
+ * @extends BI.NodeButton
+ */
+BI.SimpleSelectDataLevel1Node = BI.inherit(BI.NodeButton, {
+    _defaultConfig: function () {
+        return BI.extend(BI.SimpleSelectDataLevel1Node.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-simple-select-data-level1-node bi-list-item",
+            id: "",
+            pId: "",
+            open: false,
+            height: 25
+        })
+    },
+    _init: function () {
+        BI.SimpleSelectDataLevel1Node.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.checkbox = BI.createWidget({
+            type: "bi.tree_group_node_checkbox"
+        });
+        this.text = BI.createWidget({
+            type: "bi.label",
+            textAlign: "left",
+            whiteSpace: "nowrap",
+            textHeight: o.height,
+            height: o.height,
+            hgap: o.hgap,
+            text: o.text,
+            value: o.value,
+            py: o.py
+        });
+        this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) {
+            if(type ===  BI.Events.CLICK) {
+                self.setSelected(self.isSelected());
+            }
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        BI.createWidget({
+            type: "bi.htape",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.layout"
+                },
+                width: 10
+            },{
+                width: 23,
+                el: this.checkbox
+            }, {
+                el: this.text
+            }]
+        })
+    },
+
+    doRedMark: function () {
+        this.text.doRedMark.apply(this.text, arguments);
+    },
+
+    unRedMark: function () {
+        this.text.unRedMark.apply(this.text, arguments);
+    },
+
+    doClick: function () {
+        BI.SimpleSelectDataLevel1Node.superclass.doClick.apply(this, arguments);
+        this.checkbox.setSelected(this.isOpened());
+    },
+
+    setOpened: function (v) {
+        BI.SimpleSelectDataLevel1Node.superclass.setOpened.apply(this, arguments);
+        this.checkbox.setSelected(v);
+    },
+
+    setEnable: function (b) {
+        BI.SimpleSelectDataLevel1Node.superclass.setEnable.apply(this, arguments);
+        this.checkbox.setEnable(b);
+    }
+});
+
+$.shortcut("bi.simple_select_data_level1_node", BI.SimpleSelectDataLevel1Node);
\ No newline at end of file
diff --git a/src/widget/singleslider/singleslider.js b/src/widget/singleslider/singleslider.js
new file mode 100644
index 000000000..e962f3373
--- /dev/null
+++ b/src/widget/singleslider/singleslider.js
@@ -0,0 +1,287 @@
+/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.SingleSlider = BI.inherit(BI.Widget, {
+    _constant: {
+        EDITOR_WIDTH: 90,
+        EDITOR_HEIGHT: 30,
+        HEIGHT: 28,
+        SLIDER_WIDTH_HALF: 15,
+        SLIDER_WIDTH: 30,
+        SLIDER_HEIGHT: 30,
+        TRACK_HEIGHT: 24
+    },
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleSlider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider bi-slider-track"
+        });
+    },
+    _init: function () {
+        BI.SingleSlider.superclass._init.apply(this, arguments);
+
+        var self = this;
+        var c = this._constant;
+        this.enable = false;
+        this.value = "";
+
+        this.backgroundTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "background-track",
+            height: c.TRACK_HEIGHT
+        });
+        this.grayTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "gray-track",
+            height: 8
+        });
+        this.blueTrack = BI.createWidget({
+            type: "bi.layout",
+            cls: "blue-track",
+            height: 8
+        });
+        this.track = this._createTrackWrapper();
+
+        this.slider = BI.createWidget({
+            type: "bi.single_slider_slider"
+        });
+        this.slider.element.draggable({
+            axis: "x",
+            containment: this.grayTrack.element,
+            scroll: false,
+            drag: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));//直接对计算出来的百分数保留到小数点后一位,相当于分成了1000份。
+                self._setBlueTrack(significantPercent);
+                self._setLabelPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.label.setValue(v);
+                self.value = v;
+            },
+            stop: function (e, ui) {
+                var percent = (ui.position.left) * 100 / (self._getGrayTrackLength());
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setSliderPosition(significantPercent);
+                self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+            }
+        });
+        var sliderVertical = BI.createWidget({
+            type: "bi.vertical",
+            items: [{
+                type: "bi.absolute",
+                items: [this.slider]
+            }],
+            hgap: c.SLIDER_WIDTH_HALF,
+            height: c.SLIDER_HEIGHT
+        });
+        sliderVertical.element.click(function (e) {
+            if (self.enable) {
+                var offset = e.clientX - self.element.offset().left - c.SLIDER_WIDTH_HALF;
+                var trackLength = self.track.element[0].scrollWidth;
+                var percent = 0;
+                if (offset < 0) {
+                    percent = 0
+                }
+                if (offset > 0 && offset < (trackLength - c.SLIDER_WIDTH)) {
+                    percent = offset * 100 / self._getGrayTrackLength();
+                }
+                if (offset > (trackLength - c.SLIDER_WIDTH)) {
+                    percent = 100
+                }
+                var significantPercent = BI.parseFloat(percent.toFixed(1));
+                self._setAllPosition(significantPercent);
+                var v = self._getValueByPercent(significantPercent);
+                self.label.setValue(v);
+                self.value = v;
+                self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+            }
+        });
+        this.label = BI.createWidget({
+            type: "bi.sign_editor",
+            cls: "slider-editor-button",
+            errorText: "",
+            height: c.HEIGHT,
+            width: c.EDITOR_WIDTH,
+            allowBlank: false,
+            validationChecker: function (v) {
+                return self._checkValidation(v);
+            },
+            quitChecker: function (v) {
+                return self._checkValidation(v);
+            }
+        });
+        this.label.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var percent = self._getPercentByValue(this.getValue());
+            var significantPercent = BI.parseFloat(percent.toFixed(1));
+            self._setAllPosition(significantPercent);
+            self.fireEvent(BI.SingleSlider.EVENT_CHANGE);
+        });
+        this._setVisible(false);
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.track,
+                            width: "100%",
+                            height: c.TRACK_HEIGHT
+                        }]
+                    }],
+                    hgap: 7,
+                    height: c.TRACK_HEIGHT
+                },
+                top: 33,
+                left: 0,
+                width: "100%"
+            }, {
+                el: sliderVertical,
+                top: 30,
+                left: 0,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [this.label]
+                    }],
+                    rgap: c.EDITOR_WIDTH,
+                    height: c.EDITOR_HEIGHT
+                },
+                top: 0,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _createTrackWrapper: function () {
+        return BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.backgroundTrack,
+                width: "100%"
+            }, {
+                el: {
+                    type: "bi.vertical",
+                    items: [{
+                        type: "bi.absolute",
+                        items: [{
+                            el: this.grayTrack,
+                            top: 0,
+                            left: 0,
+                            width: "100%"
+                        }, {
+                            el: this.blueTrack,
+                            top: 0,
+                            left: 0,
+                            width: "0%"
+                        }]
+                    }],
+                    hgap: 8,
+                    height: 8
+                },
+                top: 8,
+                left: 0,
+                width: "100%"
+            }]
+        })
+    },
+
+    _checkValidation: function (v) {
+        return !(BI.isNull(v) || v < this.min || v > this.max)
+    },
+
+    _setBlueTrack: function (percent) {
+        this.blueTrack.element.css({"width": percent + "%"});
+    },
+
+    _setLabelPosition: function (percent) {
+        this.label.element.css({"left": percent + "%"});
+    },
+
+    _setSliderPosition: function (percent) {
+        this.slider.element.css({"left": percent + "%"});
+    },
+
+    _setAllPosition: function (percent) {
+        this._setSliderPosition(percent);
+        this._setLabelPosition(percent);
+        this._setBlueTrack(percent);
+    },
+
+    _setVisible: function (visible) {
+        this.slider.setVisible(visible);
+        this.label.setVisible(visible);
+    },
+
+    _getGrayTrackLength: function () {
+        return this.grayTrack.element[0].scrollWidth
+    },
+
+    _getValueByPercent: function (percent) {
+        var thousandth = BI.parseInt(percent * 10);
+        return (((this.max - this.min) * thousandth) / 1000 + this.min);
+    },
+
+    _getPercentByValue: function (v) {
+        return (v - this.min) * 100 / (this.max - this.min);
+    },
+
+    getValue: function () {
+        return this.value;
+    },
+
+    setValue: function (v) {
+        var value = BI.parseFloat(v);
+        if ((!isNaN(value))) {
+            if (this._checkValidation(value)) {
+                this.value = value;
+            }
+            if (value > this.max) {
+                this.value = this.max;
+            }
+            if (value < this.min) {
+                this.value = this.min;
+            }
+        }
+    },
+
+    setMinAndMax: function (v) {
+        var minNumber = BI.parseFloat(v.min);
+        var maxNumber = BI.parseFloat(v.max);
+        if ((!isNaN(minNumber)) && (!isNaN(maxNumber)) && (maxNumber > minNumber )) {
+            this.min = minNumber;
+            this.max = maxNumber;
+        }
+    },
+
+    reset: function () {
+        this._setVisible(false);
+        this.enable = false;
+        this.value = "";
+        this.min = 0;
+        this.max = 0;
+        this._setBlueTrack(0);
+    },
+
+    populate: function () {
+        if (!isNaN(this.min) && !isNaN(this.max)) {
+            this._setVisible(true);
+            this.enable = true;
+            this.label.setErrorText(BI.i18nText("BI-Please_Enter") + this.min + "-" + this.max + BI.i18nText("BI-Basic_De") + BI.i18nText("BI-Basic_Number"));
+            if (BI.isNumeric(this.value) || BI.isNotEmptyString(this.value)) {
+                this.label.setValue(this.value);
+                this._setAllPosition(this._getPercentByValue(this.value));
+            } else {
+                this.label.setValue(this.max);
+                this._setAllPosition(100);
+            }
+        }
+    }
+});
+BI.SingleSlider.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.single_slider", BI.SingleSlider);
\ No newline at end of file
diff --git a/src/widget/singleslider/slider/widget.slider.js b/src/widget/singleslider/slider/widget.slider.js
new file mode 100644
index 000000000..58118c464
--- /dev/null
+++ b/src/widget/singleslider/slider/widget.slider.js
@@ -0,0 +1,33 @@
+/**
+ * Created by zcf on 2016/9/22.
+ */
+BI.Slider = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.Slider.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-slider-slider"
+        });
+    },
+    _init: function () {
+        BI.extend(BI.Slider.superclass._init.apply(this, arguments));
+        this.slider = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "widget-slider-icon",
+            iconWidth: 30,
+            iconHeight: 30,
+            height: 30,
+            width: 30
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.slider,
+                top: 0,
+                left: -15
+            }],
+            width: 0,
+            height: 30
+        });
+    }
+});
+$.shortcut("bi.single_slider_slider", BI.Slider);
\ No newline at end of file
diff --git a/src/widget/singletree/singletree.combo.js b/src/widget/singletree/singletree.combo.js
new file mode 100644
index 000000000..429b7d94b
--- /dev/null
+++ b/src/widget/singletree/singletree.combo.js
@@ -0,0 +1,74 @@
+/**
+ * @class BI.SingleTreeCombo
+ * @extends BI.Widget
+ */
+BI.SingleTreeCombo = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreeCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-combo",
+            trigger: {},
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreeCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget(BI.extend({
+            type: "bi.single_tree_trigger",
+            text: o.text,
+            height: o.height,
+            items: o.items
+        }, o.trigger));
+
+        this.popup = BI.createWidget({
+            type: "bi.single_tree_popup",
+            items: o.items
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            adjustLength: 2,
+            el: this.trigger,
+            popup: {
+                el: this.popup
+            }
+        });
+
+        this.combo.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.fireEvent(BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW, arguments);
+        });
+
+        this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.SingleTreeCombo.EVENT_CHANGE);
+        });
+    },
+
+    populate: function (items) {
+        this.combo.populate(items);
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+
+BI.SingleTreeCombo.EVENT_CHANGE = "SingleTreeCombo.EVENT_CHANGE";
+BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW";
+$.shortcut("bi.single_tree_combo", BI.SingleTreeCombo);
\ No newline at end of file
diff --git a/src/widget/singletree/singletree.popup.js b/src/widget/singletree/singletree.popup.js
new file mode 100644
index 000000000..2a8eba072
--- /dev/null
+++ b/src/widget/singletree/singletree.popup.js
@@ -0,0 +1,63 @@
+/**
+ * @class BI.SingleTreePopup
+ * @extends BI.Pane
+ */
+
+BI.SingleTreePopup = BI.inherit(BI.Pane, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreePopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-popup",
+            tipText: BI.i18nText("BI-No_Selected_Item"),
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreePopup.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.tree = BI.createWidget({
+            type: 'bi.level_tree',
+            expander: {
+                isDefaultInit: true
+            },
+            items: o.items,
+            chooseType: BI.Selection.Single
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            element: this,
+            items: [this.tree]
+        });
+
+        this.tree.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+
+        this.tree.on(BI.LevelTree.EVENT_CHANGE, function () {
+            self.fireEvent(BI.SingleTreePopup.EVENT_CHANGE);
+        });
+
+        this.check();
+    },
+
+    getValue: function () {
+        return this.tree.getValue();
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.tree.setValue(v);
+    },
+
+    populate: function (items) {
+        BI.SingleTreePopup.superclass.populate.apply(this, arguments);
+        this.tree.populate(items);
+    }
+});
+
+BI.SingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.single_tree_popup", BI.SingleTreePopup);
\ No newline at end of file
diff --git a/src/widget/singletree/singletree.trigger.js b/src/widget/singletree/singletree.trigger.js
new file mode 100644
index 000000000..bb639cf83
--- /dev/null
+++ b/src/widget/singletree/singletree.trigger.js
@@ -0,0 +1,59 @@
+/**
+ * @class BI.SingleTreeTrigger
+ * @extends BI.Trigger
+ */
+
+BI.SingleTreeTrigger = BI.inherit(BI.Trigger, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SingleTreeTrigger.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-single-tree-trigger",
+            height: 30,
+            text: "",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SingleTreeTrigger.superclass._init.apply(this, arguments);
+
+        var self = this, o = this.options;
+
+        this.trigger = BI.createWidget({
+            type: "bi.select_text_trigger",
+            element: this,
+            text: o.text,
+            items: o.items,
+            height: o.height
+        });
+    },
+
+    _checkTitle: function () {
+        var self = this, val = this.getValue();
+        BI.any(this.options.items, function (i, item) {
+            if (val.contains(item.value)) {
+                self.trigger.setTitle(item.text || item.value);
+                return true;
+            }
+        });
+    },
+
+    setValue: function (v) {
+        v = BI.isArray(v) ? v : [v];
+        this.options.value = v;
+        this.trigger.setValue(v);
+        this._checkTitle();
+    },
+
+    getValue: function () {
+        return this.options.value || [];
+    },
+
+    populate: function (items) {
+        BI.SingleTreeTrigger.superclass.populate.apply(this, arguments);
+        this.trigger.populate(items);
+    }
+
+});
+
+$.shortcut("bi.single_tree_trigger", BI.SingleTreeTrigger);
\ No newline at end of file
diff --git a/src/widget/sortabletable/sortabletable.dashline.horizontal.js b/src/widget/sortabletable/sortabletable.dashline.horizontal.js
new file mode 100644
index 000000000..409a3d98f
--- /dev/null
+++ b/src/widget/sortabletable/sortabletable.dashline.horizontal.js
@@ -0,0 +1,61 @@
+BI.HorizontalDashLine = BI.inherit(BI.Widget, {
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.HorizontalDashLine.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:"bi-svg-line-horizontal",
+            gap:5,
+            line:8,
+            stroke: "#009de3",
+            fill:"white",
+            height:3,
+            width:200
+        })
+    },
+
+    _init: function () {
+        BI.HorizontalDashLine.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        this.setMove()
+    },
+
+    setLength : function (w) {
+        if(w === this.options.width){
+            return;
+        }
+        BI.HorizontalDashLine.superclass.setWidth.apply(this, arguments);
+        var o = this.options;
+        this.setMove()
+    },
+
+
+    setMove:function() {
+        var o = this.options;
+        this.svg.clear();
+        this.svg.path(this._createPath(0)).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+    },
+
+    _createPath : function (startPos) {
+        var o = this.options;
+        var path ="";
+        for(var j = 0; j < o.height; j++) {
+            for(var i = startPos - o.line; i < o.width; i+= o.line) {
+                path +="M" + (i + j)+ ","+ j
+                path +="L" + (i + j + o.line) + "," + j
+                i+= o.gap
+            }
+        }
+        return path;
+    }
+
+})
+$.shortcut("bi.horizontal_dash_line", BI.HorizontalDashLine);
\ No newline at end of file
diff --git a/src/widget/sortabletable/sortabletable.dashline.vertical.js b/src/widget/sortabletable/sortabletable.dashline.vertical.js
new file mode 100644
index 000000000..19defe1ac
--- /dev/null
+++ b/src/widget/sortabletable/sortabletable.dashline.vertical.js
@@ -0,0 +1,60 @@
+BI.VerticalDashLine = BI.inherit(BI.Widget, {
+
+
+    _defaultConfig: function () {
+        return BI.extend(BI.VerticalDashLine.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:"bi-svg-line-vertical",
+            gap:5,
+            line:8,
+            stroke: "#009de3",
+            fill:"white",
+            height:200,
+            width:3
+        })
+    },
+
+    _init: function () {
+        BI.VerticalDashLine.superclass._init.apply(this, arguments);
+        var o = this.options;
+        this.svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        this.setMove()
+    },
+
+    setLength : function (w) {
+        if(w === this.options.height){
+            return;
+        }
+        BI.VerticalDashLine.superclass.setHeight.apply(this, arguments);
+        this.setMove()
+    },
+
+
+    setMove:function() {
+        var o = this.options;
+        this.svg.clear();
+        this.svg.path(this._createPath(0)).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+    },
+
+    _createPath : function (startPos) {
+        var o = this.options;
+        var path ="";
+        for(var j = 0; j < o.width; j++) {
+            for(var i = startPos - o.line; i < o.height; i+= o.line) {
+                path +="M"+ j + "," + (i + j)
+                path +="L" + j + "," + (i + j + o.line)
+                i+= o.gap
+            }
+        }
+        return path;
+    }
+
+})
+$.shortcut("bi.vertical_dash_line", BI.VerticalDashLine);
\ No newline at end of file
diff --git a/src/widget/sortabletable/sortabletable.drag.button.js b/src/widget/sortabletable/sortabletable.drag.button.js
new file mode 100644
index 000000000..8c0a0762f
--- /dev/null
+++ b/src/widget/sortabletable/sortabletable.drag.button.js
@@ -0,0 +1,46 @@
+BI.TriangleDragButton = BI.inherit(BI.Widget, {
+    _defaultConfig: function() {
+        return BI.extend(BI.TriangleDragButton.superclass._defaultConfig.apply(this, arguments), {
+            baseCls:  "bi-triangle-drag-button",
+            height : 30,
+            width : 30,
+            lineCount:6,
+            stroke: "#009de3",
+            fill:"white",
+            drag : null
+        })
+    },
+
+
+    _init : function() {
+        BI.TriangleDragButton.superclass._init.apply(this, arguments);
+        var o = this.options;
+        var svg = BI.createWidget({
+            type:"bi.svg",
+            element: this,
+            height: o.height,
+            width: o.width
+        })
+        var path = "";
+        var h_step = o.height/ o.lineCount;
+        var w_step = o.width/ o.lineCount;
+        for(var i = 0; i < o.lineCount; i++){
+            path +="M0," +(h_step * (i + 1));
+            path +="L" + (w_step * (i + 1)) +",0"
+        }
+        svg.path(path).attr({
+            stroke: o.stroke,
+            fill: o.fill
+        })
+        this.reInitDrag();
+    },
+
+    reInitDrag : function () {
+        var o = this.options;
+        if(BI.isNotNull(o.drag)) {
+            this.element.draggable(o.drag)
+        }
+    }
+});
+
+$.shortcut("bi.triangle_drag_button", BI.TriangleDragButton);
\ No newline at end of file
diff --git a/src/widget/sortabletable/sortabletable.js b/src/widget/sortabletable/sortabletable.js
new file mode 100644
index 000000000..1e1444d95
--- /dev/null
+++ b/src/widget/sortabletable/sortabletable.js
@@ -0,0 +1,366 @@
+/**
+ * 可以交换列位置的表格
+ *
+ * @class BI.SortableTable
+ * @extends BI.Widget
+ */
+BI.SortableTable = BI.inherit(BI.Widget, {
+
+    _const: {
+        perColumnSize: 100,
+        dragButtonWidth: 24,
+        dragButtonHeight: 24,
+        lineCount: 6,
+        lineWidth: 3
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SortableTable.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-sortable-table",
+
+            headerRowSize: 30,
+            footerRowSize: 25,
+            rowSize: 25,
+            sortable: true,
+
+            header: [],
+            items: [] //二维数组
+        });
+    },
+
+    _init: function () {
+        BI.SortableTable.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.insertLine = [];
+
+        this.table = BI.createWidget({
+            type: "bi.table_view",
+            isNeedResize: false,
+            isResizeAdapt: false,
+            columnSize: [],
+            headerRowSize: o.headerRowSize,
+            footerRowSize: o.footerRowSize,
+            rowSize: o.rowSize,
+            regionColumnSize: false,
+            header: o.header,
+            items: o.items
+        });
+        this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () {
+            if(o.sortable === true){
+                self._initDrag();
+                self._createDashedLines();
+                self._createInsertLine();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments);
+        });
+        this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () {
+            if(o.sortable === true){
+                self._createDashedLines();
+                self._createInsertLine();
+            }
+            self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments);
+        });
+
+        this.table.element.mousemove(function(e){
+            BI.each(self.dragHelpers, function(idx, dragHelper){
+                var visible = (idx === self._getMouseInColumnIndex(e));
+                dragHelper.setVisible(visible);
+                BI.each(self.dragHelpersLines[idx], function(id, line){
+                    line.setVisible(visible);
+                })
+            })
+        })
+
+        this.table.element.hover(function(e){
+        }, function(e){
+            BI.each(self.dragHelpers, function(idx, dragHelper){
+                dragHelper.setVisible(false);
+                BI.each(self.dragHelpersLines[idx], function(id, line){
+                    line.setVisible(false);
+                })
+            })
+        });
+
+        this.element.droppable({
+            accept: ".drag-header",
+            drop: function (e, ui) {
+                var absolutePosition = ui.position.left + self.table.getRightHorizontalScroll() + (e.pageX - ui.helper.offset().left);
+                var dropPosition = self._getColumnsLeftBorderDistance();
+                var insertIndex = self._getNearIndexFromArray(dropPosition, absolutePosition)
+                //这个insertIndex是包含原元素的index
+                //调整item顺序,重新populate
+                var flag = self._exchangeItemsAndHeaderPosition(ui.helper.data("index"), insertIndex)
+                if(flag === true){
+                    BI.nextTick(function(){
+                        self.populate(o.items, o.header);
+                    });
+                    self.fireEvent(BI.SortableTable.EVENT_CHANGE, ui.helper.data("index"), insertIndex);
+                }
+            }
+        });
+
+        BI.createWidget({
+            type: "bi.vertical",
+            scrollx: false,
+            element: this,
+            items: [this.table]
+        });
+    },
+
+    /**
+     * 插入到对应列的辅助线
+     * @private
+     */
+    _createInsertLine: function(){
+        var self = this;
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var height = this.table.getClientRegionRowSize()[0];
+        var lineObj = {
+            type: "bi.layout",
+            cls: "insert-help-line",
+            invisible: true
+        };
+        this.insertLine = [BI.createWidget(lineObj)];
+        var hearders = this.table.getColumns().header[0];
+        BI.each(hearders, function(idx, header){
+            var line = BI.createWidget(BI.extend(lineObj));
+            self.insertLine.push(line);
+        });
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this.table.element,
+            items: BI.map(self.insertLine, function(idx, line){
+                if(idx === self.insertLine.length - 1){
+                    return {
+                        el: line,
+                        top: 0,
+                        height: height,
+                        right: 0
+                    }
+                }
+                return {
+                    el: line,
+                    top: 0,
+                    height: height,
+                    left: dropPosition[idx]
+                }
+            })
+        })
+    },
+
+    _createDashedLines: function(){
+        var self = this, c = this._const, o = this.options;
+        var RowsSize = this.table.getClientRegionRowSize();
+        var columnsSizes = this.table.getCalculateColumnSize();
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var len = this.table.getCalculateRegionColumnSize()[0];
+        this.dragHelpersLines = [];
+        BI.each(this.table.getColumns().header[0], function(idx, header){
+            self.dragHelpersLines.push([BI.createWidget({
+                type:"bi.horizontal_dash_line",      //上
+                width: columnsSizes[idx],
+                height: c.lineWidth,
+                invisible: true
+            }),BI.createWidget({
+                type:"bi.vertical_dash_line",        //右
+                width: c.lineWidth,
+                height: RowsSize[0],
+                invisible: true
+            }),BI.createWidget({
+                type:"bi.horizontal_dash_line",      //下
+                width: columnsSizes[idx],
+                height: c.lineWidth,
+                invisible: true
+            }),BI.createWidget({                //左
+                type:"bi.vertical_dash_line",
+                width: c.lineWidth,
+                height: RowsSize[0],
+                invisible: true
+            })]);
+        });
+        var length = this.dragHelpersLines.length;
+        BI.createWidget({
+            type: "bi.absolute",
+            element: self.table,
+            items: BI.flatten(BI.map(this.dragHelpersLines, function(idx, children){
+                return BI.map(children, function(id, child){
+                    var baseObj = {
+                        el: child,
+                        width: id % 2 === 0 ? columnsSizes[idx] : c.lineWidth,
+                        height: id % 2 === 0 ? c.lineWidth : RowsSize[0]
+                    }
+                    if(id === 0 || id === children.length - 1){     //上和左
+                        return BI.extend({
+                            top: 0,
+                            left: dropPosition[idx],
+                        }, baseObj)
+                    }else{
+                        return BI.extend({                                    //右和下
+                            bottom: 0,
+                            right:  idx === length - 1 ? 0 : len - dropPosition[idx + 1],
+                        }, baseObj)
+                    }
+                });
+            }))
+        })
+    },
+
+    _initDrag: function(){
+        var self = this, c = this._const, o = this.options;
+        this.dragHelpers = [];
+        BI.each(this.table.getColumns().header[0], function(idx, header){
+            var dragButton = BI.createWidget({
+                type: "bi.triangle_drag_button",
+                cls: "drag-header",
+                width: c.dragButtonWidth,
+                height: c.dragButtonHeight,
+                lineCount: c.lineCount,
+                invisible: true
+            });
+            BI.createWidget({
+                type: "bi.absolute",
+                element: header,
+                items: [{
+                    el: dragButton,
+                    top: 0,
+                    left: 0
+                }]
+            })
+
+            dragButton.element.draggable({
+                axis: "x",      //拖拽路径
+                revert: false,
+                cursor: BICst.cursorUrl,
+                cursorAt: {left: 5, top: 5},
+                containment: self.element,   //约束拖拽区域
+                drag: function(e, ui){
+                    self._showInsertHelpLine(e, ui);
+                },
+                stop: function(){
+                    BI.each(self.insertLine, function(idx, line){
+                        line.setVisible(false);
+                    })
+                },
+                helper: function () {
+                    var RowsSize = self.table.getClientRegionRowSize();
+                    var columnsSizes = self.table.getCalculateColumnSize();
+                    var clone = BI.createWidget({
+                        type: "bi.layout",
+                        cls: "sortable_table_drag_clone",
+                        data: {index: BI.parseInt(idx)},
+                        width: columnsSizes[idx],
+                        height: RowsSize[0]
+                    })
+                    clone.element.appendTo(self.element);
+                    return clone.element;
+                }
+            })
+            self.dragHelpers.push(dragButton);
+        });
+    },
+
+    _getMouseInColumnIndex: function(e){
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var columnsSizes = this.table.getCalculateColumnSize();
+        var tableHeight = this.table.getClientRegionRowSize()[0];
+        var tableOffsetLeft = e.pageX - this.table.element.offset().left;
+        var tableOffsetTop = this.table.element.offset().top;
+        return BI.find(BI.makeArray(dropPosition.length, null), function(idx){
+            return !(tableOffsetLeft < dropPosition[idx] || tableOffsetLeft > dropPosition[idx] + columnsSizes[idx]
+            || e.pageY < tableOffsetTop || e.pageY >= tableOffsetTop + tableHeight);
+        })
+    },
+
+    _getColumnsLeftBorderDistance: function(){
+        var dropPosition = [];
+        var columnSizes = this.table.getCalculateColumnSize();
+        BI.each(columnSizes, function(idx, columnSize){
+            if(idx === 0){
+                dropPosition.push(0)
+            }else{
+                //+ 1边框偏移值
+                dropPosition.push(dropPosition[idx - 1] + columnSizes[idx - 1] + 1)
+            }
+        });
+        return dropPosition;
+    },
+
+    _showInsertHelpLine: function(e, ui){
+        var absolutePosition =  ui.position.left + this.table.getRightHorizontalScroll() + (e.pageX - ui.helper.offset().left);
+        var dropPosition = this._getColumnsLeftBorderDistance();
+        var insertIndex = this._getNearIndexFromArray(dropPosition, absolutePosition);
+        BI.each(this.insertLine, function(idx, line){
+            line.setVisible(insertIndex === idx);
+        })
+        BI.each(this.dragHelpers, function(idx, helper){
+            helper.setVisible(false);
+        })
+    },
+
+    _exchangeItemsAndHeaderPosition: function (sourceIndex, targetIndex) {
+        var o = this.options;
+        if(sourceIndex === targetIndex){
+            return false;
+        }
+        var header = BI.unzip(o.header);
+        var items = BI.unzip(o.items);
+        var sourceHeader = header[sourceIndex];
+        var sourceitems = items[sourceIndex];
+        header.splice(targetIndex, 0, sourceHeader);
+        items.splice(targetIndex, 0, sourceitems);
+        var deleteIndex = (sourceIndex < targetIndex) ? sourceIndex : sourceIndex + 1;
+        BI.removeAt(header, deleteIndex);
+        BI.removeAt(items, deleteIndex);
+        o.header = BI.unzip(header);
+        o.items = BI.unzip(items);
+        return true;
+    },
+
+    _getNearIndexFromArray: function (array, v) {
+        var self = this;
+        var index = 0;
+        BI.some(array, function (idx, item) {
+            if (idx === array.length - 1) {
+                index = idx;
+                //如果是最后一列,且鼠标位置超出最后一列的中间位置,表示插入到最后
+                var len = self.table.getCalculateRegionColumnSize()[0];
+                var columnSizes = self.table.getCalculateColumnSize();
+                if(v > len - columnSizes[idx] / 2){
+                    index++;
+                }
+            } else {
+                if (v < array[idx + 1]) {
+                    var avg = (item + array[idx + 1]) / 2;
+
+                    index = v < avg ? idx : idx + 1;
+                    return true;
+                }
+            }
+        })
+        return index;
+    },
+
+    getColumns: function(){
+        return this.table.getColumns();
+    },
+
+    setSortable: function(sortable){
+        this.options.sortable = sortable;
+    },
+
+    populate: function (items, headers) {
+        var self = this, o = this.options;
+        o.header = headers;
+        o.items = items;
+        self.table.populate(o.items, o.header);
+    },
+
+    destroy: function () {
+        this.table.destroy();
+        BI.SortableTable.superclass.destroy.apply(this, arguments);
+    }
+});
+
+BI.SortableTable.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut('bi.sortable_table', BI.SortableTable);
\ No newline at end of file
diff --git a/src/widget/switchtree/switchtree.js b/src/widget/switchtree/switchtree.js
new file mode 100644
index 000000000..1c29abfe5
--- /dev/null
+++ b/src/widget/switchtree/switchtree.js
@@ -0,0 +1,111 @@
+/**
+ * 可以单选多选切换的树
+ *
+ * Created by GUY on 2015/12/21.
+ * @class BI.SwitchTree
+ * @extends BI.Widget
+ */
+BI.SwitchTree = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.SwitchTree.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-switch-tree",
+            items: []
+        });
+    },
+
+    _init: function () {
+        BI.SwitchTree.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.tab = BI.createWidget({
+            type: "bi.tab",
+            element: this,
+            tab: null,
+            defaultShowIndex: BI.SwitchTree.SelectType.SingleSelect,
+            cardCreator: BI.bind(this._createTree, this)
+        });
+    },
+
+    _createTree: function (type) {
+        var self = this, o = this.options;
+        switch (type) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.levelTree = BI.createWidget({
+                    type: "bi.multilayer_single_level_tree",
+                    isDefaultInit: true,
+                    items: BI.deepClone(o.items)
+                });
+                this.levelTree.on(BI.LevelTree.EVENT_CHANGE, function () {
+                    self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments);
+                });
+                return this.levelTree;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.tree = BI.createWidget({
+                    type: "bi.simple_tree",
+                    items: this._removeIsParent(BI.deepClone(o.items))
+                });
+                this.tree.on(BI.SimpleTreeView.EVENT_CHANGE, function () {
+                    self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments);
+                });
+                return this.tree;
+        }
+    },
+
+    _removeIsParent: function(items) {
+        BI.each(items, function(i, item) {
+            BI.isNotNull(item.isParent) && delete item.isParent;
+        });
+        return items;
+    },
+
+    switchSelect: function () {
+        switch (this.getSelect()) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.setSelect(BI.SwitchTree.SelectType.MultiSelect);
+                break;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.setSelect(BI.SwitchTree.SelectType.SingleSelect);
+                break;
+        }
+    },
+
+    setSelect: function (v) {
+        this.tab.setSelect(v);
+    },
+
+    getSelect: function () {
+        return this.tab.getSelect();
+    },
+
+    setValue: function (v) {
+        this.storeValue = v;
+        switch (this.getSelect()) {
+            case BI.SwitchTree.SelectType.SingleSelect:
+                this.levelTree.setValue(v);
+                break;
+            case BI.SwitchTree.SelectType.MultiSelect:
+                this.tree.setValue(v);
+                break;
+        }
+    },
+
+    getValue: function () {
+        return this.tab.getValue();
+    },
+
+    populate: function (items) {
+        this.options.items = items;
+        if (BI.isNotNull(this.levelTree)) {
+            this.levelTree.populate(BI.deepClone(items));
+        }
+        if (BI.isNotNull(this.tree)) {
+            this.tree.populate(this._removeIsParent(BI.deepClone(items)));
+        }
+    }
+});
+BI.SwitchTree.EVENT_CHANGE = "SwitchTree.EVENT_CHANGE";
+BI.SwitchTree.SelectType = {
+    SingleSelect: BI.Selection.Single,
+    MultiSelect: BI.Selection.Multi
+};
+$.shortcut('bi.switch_tree', BI.SwitchTree);
diff --git a/src/widget/textarea/textarea.js b/src/widget/textarea/textarea.js
new file mode 100644
index 000000000..c2c2345cb
--- /dev/null
+++ b/src/widget/textarea/textarea.js
@@ -0,0 +1,125 @@
+/**
+ * 文本组件中 编辑栏作为trigger
+ *
+ * Created by GameJian on 2016/1/24.
+ */
+BI.TextArea = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextArea.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-area"
+        });
+    },
+
+    _init: function () {
+        BI.TextArea.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.textarea = BI.createWidget({
+            type: "bi.textarea_editor",
+            width: "100%",
+            height: "100%"
+        });
+
+        this.textarea.on(BI.TextAreaEditor.EVENT_FOCUS, function () {
+            self.combo.showView();
+        });
+
+        this.textarea.on(BI.TextAreaEditor.EVENT_BLUR, function () {
+            if (BI.isEmptyString(this.getValue()) && !self.combo.isViewVisible()) {
+                self._showLabel();
+            } else {
+                self._showInput();
+            }
+            self.fireEvent(BI.TextArea.EVENT_VALUE_CHANGE, arguments)
+        });
+
+        this.toolbar = BI.createWidget({
+            type: "bi.text_toolbar"
+        });
+
+        this.toolbar.on(BI.TextToolbar.EVENT_CHANGE, function () {
+            var style = this.getValue();
+            self.textarea.setStyle(style);
+            self.element.css(style);
+            self.fireEvent(BI.TextArea.EVENT_VALUE_CHANGE, arguments);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            toggle: false,
+            direction: "top",
+            isNeedAdjustWidth: false,
+            isNeedAdjustHeight: false,
+            adjustLength: 1,
+            el: this.textarea,
+            popup: {
+                el: this.toolbar,
+                width: 253,
+                height: 30,
+                stopPropagation: false
+            }
+        });
+
+        this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () {
+            if (BI.isNotEmptyString(self.textarea.getValue())) {
+                self._showInput();
+            } else {
+                self._showLabel();
+            }
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.text_button",
+            cls: "text-area-editor-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-Click_To_Input_Text")
+        });
+
+        this.label.on(BI.TextButton.EVENT_CHANGE, function () {
+            self._showInput();
+            self.textarea.focus();
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.combo,
+                left: 10,
+                right: 10,
+                top: 10,
+                bottom: 10
+            }, {
+                el: this.label,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    _showInput: function () {
+        this.label.setVisible(false);
+    },
+
+    _showLabel: function () {
+        this.label.setVisible(true);
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        if (BI.isNotEmptyString(v.content)) {
+            this._showInput();
+        }
+        this.textarea.setValue(v.content);
+        this.toolbar.setValue(v.style);
+        this.textarea.setStyle(v.style);
+        this.element.css(v.style);
+    },
+
+    getValue: function () {
+        return {style: this.toolbar.getValue(), content: this.textarea.getValue()};
+    }
+});
+BI.TextArea.EVENT_VALUE_CHANGE = "EVENT_VALUE_CHANGE";
+$.shortcut("bi.text_area", BI.TextArea);
\ No newline at end of file
diff --git a/src/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.js b/src/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.js
new file mode 100644
index 000000000..34e6fd612
--- /dev/null
+++ b/src/widget/texttoolbar/alignchooser/texttoolbar.alignchooser.js
@@ -0,0 +1,66 @@
+/**
+ * 对齐方式选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarAlignChooser
+ * @extends BI.Widget
+ */
+BI.TextToolbarAlignChooser = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbarAlignChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar-align-chooser",
+            width: 60,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarAlignChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.button_group = BI.createWidget({
+            type: "bi.button_group",
+            element: this,
+            items: BI.createItems([{
+                cls: "align-chooser-button text-align-left-font",
+                selected: true,
+                title: BI.i18nText("BI-Word_Align_Left"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_LEFT
+            }, {
+                cls: "align-chooser-button text-align-center-font",
+                title: BI.i18nText("BI-Word_Align_Middle"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_CENTER
+            }, {
+                cls: "align-chooser-button text-align-right-font",
+                title: BI.i18nText("BI-Word_Align_Right"),
+                value: BI.TextToolbarAlignChooser.TEXT_ALIGN_RIGHT
+            }], {
+                type: "bi.icon_button",
+                height: o.height
+            }),
+            layouts: [{
+                type: "bi.center"
+            }]
+        });
+        this.button_group.on(BI.Controller.EVENT_CHANGE, function () {
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+        });
+        this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbarAlignChooser.EVENT_CHANGE, arguments);
+        });
+    },
+
+    setValue: function (v) {
+        this.button_group.setValue(v);
+    },
+
+    getValue: function () {
+        return this.button_group.getValue()[0];
+    }
+});
+BI.extend(BI.TextToolbarAlignChooser, {
+    TEXT_ALIGN_LEFT: "left",
+    TEXT_ALIGN_CENTER: "center",
+    TEXT_ALIGN_RIGHT: "right"
+});
+BI.TextToolbarAlignChooser.EVENT_CHANGE = "BI.TextToolbarAlignChooser.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar_align_chooser', BI.TextToolbarAlignChooser);
\ No newline at end of file
diff --git a/src/widget/texttoolbar/backgroundchooser/texttoolbar.backgroundchooser.trigger.js b/src/widget/texttoolbar/backgroundchooser/texttoolbar.backgroundchooser.trigger.js
new file mode 100644
index 000000000..c8c8851d8
--- /dev/null
+++ b/src/widget/texttoolbar/backgroundchooser/texttoolbar.backgroundchooser.trigger.js
@@ -0,0 +1,53 @@
+/**
+ * 颜色选择trigger
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarBackgroundChooserTrigger
+ * @extends BI.Widget
+ */
+BI.TextToolbarBackgroundChooserTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        var conf = BI.TextToolbarBackgroundChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-toolbar-background-chooser-trigger",
+            width: 20,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarBackgroundChooserTrigger.superclass._init.apply(this, arguments);
+        this.font = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-background-font"
+        });
+
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-underline-font"
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.font,
+                top: 3,
+                left: 2
+            }, {
+                el: this.underline,
+                top: 9,
+                left: 2
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.underline.element.css("color", color);
+    },
+
+    getValue: function () {
+        return this.font.element.css("color");
+    }
+});
+$.shortcut('bi.text_toolbar_background_chooser_trigger', BI.TextToolbarBackgroundChooserTrigger);
\ No newline at end of file
diff --git a/src/widget/texttoolbar/colorchooser/texttoolbar.colorchooser.trigger.js b/src/widget/texttoolbar/colorchooser/texttoolbar.colorchooser.trigger.js
new file mode 100644
index 000000000..899193c35
--- /dev/null
+++ b/src/widget/texttoolbar/colorchooser/texttoolbar.colorchooser.trigger.js
@@ -0,0 +1,53 @@
+/**
+ * 颜色选择trigger
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarColorChooserTrigger
+ * @extends BI.Widget
+ */
+BI.TextToolbarColorChooserTrigger = BI.inherit(BI.Trigger, {
+    _defaultConfig: function () {
+        var conf = BI.TextToolbarColorChooserTrigger.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            baseCls: (conf.baseCls || "") + " bi-text-toolbar-color-chooser-trigger",
+            width: 20,
+            height: 20
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbarColorChooserTrigger.superclass._init.apply(this, arguments);
+        this.font = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-font"
+        });
+
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "text-color-underline-font"
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.font,
+                top: 4,
+                left: 2
+            },{
+                el: this.underline,
+                top: 9,
+                left: 2
+            }]
+        })
+    },
+
+    setValue: function (color) {
+        this.underline.element.css("color", color);
+    },
+
+    getValue: function () {
+        return this.font.element.css("color");
+    }
+});
+$.shortcut('bi.text_toolbar_color_chooser_trigger', BI.TextToolbarColorChooserTrigger);
\ No newline at end of file
diff --git a/src/widget/texttoolbar/sizechooser/texttoolbar.sizechooser.js b/src/widget/texttoolbar/sizechooser/texttoolbar.sizechooser.js
new file mode 100644
index 000000000..61d70f026
--- /dev/null
+++ b/src/widget/texttoolbar/sizechooser/texttoolbar.sizechooser.js
@@ -0,0 +1,106 @@
+/**
+ * 字体大小选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbarSizeChooser
+ * @extends BI.Widget
+ */
+BI.TextToolbarSizeChooser = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbarSizeChooser.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar-size-chooser",
+            width: 50,
+            height: 20
+        });
+    },
+
+    _items: [{
+        value: 12
+    }, {
+        value: 14,
+        selected: true
+    }, {
+        value: 16
+    }, {
+        value: 18
+    }, {
+        value: 20
+    }, {
+        value: 22
+    }, {
+        value: 24
+    }, {
+        value: 26
+    }, {
+        value: 28
+    }, {
+        value: 30
+    }, {
+        value: 32
+    }, {
+        value: 34
+    }, {
+        value: 36
+    }, {
+        value: 38
+    }, {
+        value: 40
+    }, {
+        value: 64
+    }, {
+        value: 128
+    }],
+
+    _init: function () {
+        BI.TextToolbarSizeChooser.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.trigger = BI.createWidget({
+            type: "bi.editor_trigger",
+            cls: "text-toolbar-size-chooser-editor-trigger",
+            height: o.height,
+            triggerWidth: 12,
+            validationChecker: function (size) {
+                return BI.isInteger(size) && size > 0;
+            },
+            value: 14
+        });
+        this.trigger.on(BI.EditorTrigger.EVENT_CHANGE, function () {
+            self.setValue(BI.parseInt(this.getValue()));
+            self.fireEvent(BI.TextToolbarSizeChooser.EVENT_CHANGE, arguments);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            el: this.trigger,
+            adjustLength: 1,
+            popup: {
+                maxWidth: o.width,
+                minWidth: o.width,
+                el: {
+                    type: "bi.button_group",
+                    items: BI.createItems(this._items, {
+                        type: "bi.single_select_item"
+                    }),
+                    layouts: [{
+                        type: "bi.vertical"
+                    }]
+                }
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_CHANGE, function () {
+            this.hideView();
+            self.fireEvent(BI.TextToolbarSizeChooser.EVENT_CHANGE, arguments);
+        })
+    },
+
+    setValue: function (v) {
+        this.combo.setValue(v);
+    },
+
+    getValue: function () {
+        return BI.parseInt(this.trigger.getValue());
+    }
+});
+BI.TextToolbarSizeChooser.EVENT_CHANGE = "BI.TextToolbarSizeChooser.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar_size_chooser', BI.TextToolbarSizeChooser);
\ No newline at end of file
diff --git a/src/widget/texttoolbar/texttoolbar.js b/src/widget/texttoolbar/texttoolbar.js
new file mode 100644
index 000000000..c88875a64
--- /dev/null
+++ b/src/widget/texttoolbar/texttoolbar.js
@@ -0,0 +1,130 @@
+/**
+ * 颜色选择
+ *
+ * Created by GUY on 2015/11/26.
+ * @class BI.TextToolbar
+ * @extends BI.Widget
+ */
+BI.TextToolbar = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TextToolbar.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-text-toolbar",
+            width: 253,
+            height: 28
+        });
+    },
+
+    _init: function () {
+        BI.TextToolbar.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.size = BI.createWidget({
+            type: "bi.text_toolbar_size_chooser",
+            cls: "text-toolbar-size-chooser-trigger",
+            title: BI.i18nText("BI-Font_Size")
+        });
+        this.size.on(BI.TextToolbarSizeChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.bold = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Basic_Bold"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-bold-font"
+        });
+        this.bold.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.italic = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Basic_Italic"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-italic-font"
+        });
+        this.italic.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.underline = BI.createWidget({
+            type: "bi.icon_button",
+            title: BI.i18nText("BI-Underline"),
+            height: 20,
+            width: 20,
+            cls: "text-toolbar-button bi-list-item-active text-underline-font"
+        });
+        this.underline.on(BI.IconButton.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.colorchooser = BI.createWidget({
+            type: "bi.color_chooser",
+            el: {
+                type: "bi.text_toolbar_color_chooser_trigger",
+                title: BI.i18nText("BI-Font_Colour"),
+                cls: "text-toolbar-button"
+            }
+        });
+        this.colorchooser.on(BI.ColorChooser.EVENT_CHANGE, function () {
+
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.backgroundchooser = BI.createWidget({
+            type: "bi.color_chooser",
+            el: {
+                type: "bi.text_toolbar_background_chooser_trigger",
+                title: BI.i18nText("BI-Widget_Background_Colour"),
+                cls: "text-toolbar-button"
+            }
+        });
+        this.backgroundchooser.on(BI.ColorChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+        this.alignchooser = BI.createWidget({
+            type: "bi.text_toolbar_align_chooser",
+            cls: "text-toolbar-button"
+        });
+        this.alignchooser.on(BI.TextToolbarAlignChooser.EVENT_CHANGE, function () {
+            self.fireEvent(BI.TextToolbar.EVENT_CHANGE, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [this.size, this.bold, this.italic, this.underline, this.colorchooser, this.backgroundchooser, this.alignchooser],
+            hgap: 3,
+            vgap: 3
+        })
+    },
+
+    isColorChooserVisible: function () {
+        return this.colorchooser.isViewVisible();
+    },
+
+    isBackgroundChooserVisible: function () {
+        return this.backgroundchooser.isViewVisible();
+    },
+
+    setValue: function (v) {
+        v || (v = {});
+        this.size.setValue(v["fontSize"] || 14);
+        this.bold.setSelected(v["fontWeight"] === "bold");
+        this.italic.setSelected(v["fontStyle"] === "italic");
+        this.underline.setSelected(v["textDecoration"] === "underline");
+        this.colorchooser.setValue(v["color"] || "#000000");
+        this.backgroundchooser.setValue(v["backgroundColor"] || "#ffffff");
+        this.alignchooser.setValue(v["textAlign"] || "left");
+    },
+
+    getValue: function () {
+        return {
+            "fontSize": this.size.getValue(),
+            "fontWeight": this.bold.isSelected() ? "bold" : "normal",
+            "fontStyle": this.italic.isSelected() ? "italic" : "normal",
+            "textDecoration": this.underline.isSelected() ? "underline" : "initial",
+            "color": this.colorchooser.getValue(),
+            "backgroundColor": this.backgroundchooser.getValue(),
+            "textAlign": this.alignchooser.getValue()
+        }
+    }
+});
+BI.TextToolbar.EVENT_CHANGE = "BI.TextToolbar.EVENT_CHANGE";
+$.shortcut('bi.text_toolbar', BI.TextToolbar);
\ No newline at end of file
diff --git a/src/widget/timeinterval/timeinterval.js b/src/widget/timeinterval/timeinterval.js
new file mode 100644
index 000000000..6e330e9fc
--- /dev/null
+++ b/src/widget/timeinterval/timeinterval.js
@@ -0,0 +1,189 @@
+/**
+ * Created by Baron on 2015/10/19.
+ */
+BI.TimeInterval = BI.inherit(BI.Single, {
+    constants: {
+        height: 25,
+        width: 25,
+        lgap: 15,
+        offset: -15,
+        timeErrorCls: "time-error",
+        DATE_MIN_VALUE: "1900-01-01",
+        DATE_MAX_VALUE: "2099-12-31"
+    },
+    _defaultConfig: function () {
+        var conf = BI.TimeInterval.superclass._defaultConfig.apply(this, arguments);
+        return BI.extend(conf, {
+            extraCls: "bi-time-interval"
+        })
+    },
+    _init: function () {
+        var self = this;
+        BI.TimeInterval.superclass._init.apply(this, arguments);
+
+        this.left = this._createCombo();
+        this.right = this._createCombo();
+        this.label = BI.createWidget({
+            type: 'bi.label',
+            height: this.constants.height,
+            width: this.constants.width,
+            text: "-"
+        });
+        BI.createWidget({
+            element: self,
+            type: "bi.center",
+            hgap: 15,
+            height: this.constants.height,
+            items: [{
+                type: "bi.absolute",
+                items: [{
+                    el: self.left,
+                    left: this.constants.offset,
+                    right: 0,
+                    top: 0,
+                    bottom: 0
+                }]
+            }, {
+                type: "bi.absolute",
+                items: [{
+                    el: self.right,
+                    left: 0,
+                    right: this.constants.offset,
+                    top: 0,
+                    bottom: 0
+                }]
+            }]
+        });
+        BI.createWidget({
+            type: "bi.horizontal_auto",
+            element: this,
+            items: [
+                self.label
+            ]
+        });
+    },
+
+    _createCombo: function () {
+        var self = this;
+        var combo = BI.createWidget({
+            type: 'bi.multidate_combo'
+        });
+        combo.on(BI.MultiDateCombo.EVENT_ERROR, function () {
+            self._clearTitle();
+            self.element.removeClass(self.constants.timeErrorCls);
+            self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_VALID, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+                    offsetStyle: "center"
+                });
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            } else {
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+            }
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_FOCUS, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+                    offsetStyle: "center"
+                });
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            } else {
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+            }
+        });
+
+        combo.on(BI.MultiDateCombo.EVENT_BEFORE_POPUPVIEW, function () {
+            self.left.hidePopupView();
+            self.right.hidePopupView();
+        });
+        //combo.on(BI.MultiDateCombo.EVENT_CHANGE, function () {
+        //    BI.Bubbles.hide("error");
+        //    var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+        //    if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+        //        self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+        //        self.element.addClass(self.constants.timeErrorCls);
+        //        BI.Bubbles.show("error", BI.i18nText("BI-Time_Interval_Error_Text"), self, {
+        //            offsetStyle: "center"
+        //        });
+        //        self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+        //    } else {
+        //        self._clearTitle();
+        //        self.element.removeClass(self.constants.timeErrorCls);
+        //    }
+        //});
+
+        combo.on(BI.MultiDateCombo.EVENT_CONFIRM, function(){
+            BI.Bubbles.hide("error");
+            var smallDate = self.left.getKey(), bigDate = self.right.getKey();
+            if (self._check(smallDate, bigDate) && self._compare(smallDate, bigDate)) {
+                self._setTitle(BI.i18nText("BI-Time_Interval_Error_Text"));
+                self.element.addClass(self.constants.timeErrorCls);
+                self.fireEvent(BI.TimeInterval.EVENT_ERROR);
+            }else{
+                self._clearTitle();
+                self.element.removeClass(self.constants.timeErrorCls);
+                self.fireEvent(BI.TimeInterval.EVENT_CHANGE);
+            }
+        });
+        return combo;
+    },
+    _dateCheck: function (date) {
+        return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date;
+    },
+    _checkVoid: function (obj) {
+        return !Date.checkVoid(obj.year, obj.month, obj.day, this.constants.DATE_MIN_VALUE, this.constants.DATE_MAX_VALUE)[0];
+    },
+    _check: function (smallDate, bigDate) {
+        var smallObj = smallDate.match(/\d+/g), bigObj = bigDate.match(/\d+/g);
+        return this._dateCheck(smallDate) && Date.checkLegal(smallDate) && this._checkVoid({
+                year: smallObj[0],
+                month: smallObj[1],
+                day: smallObj[2]
+            }) && this._dateCheck(bigDate) && Date.checkLegal(bigDate) && this._checkVoid({
+                year: bigObj[0],
+                month: bigObj[1],
+                day: bigObj[2]
+            });
+    },
+    _compare: function (smallDate, bigDate) {
+        smallDate = Date.parseDateTime(smallDate, "%Y-%X-%d").print("%Y-%X-%d");
+        bigDate = Date.parseDateTime(bigDate, "%Y-%X-%d").print("%Y-%X-%d");
+        return BI.isNotNull(smallDate) && BI.isNotNull(bigDate) && smallDate > bigDate;
+    },
+    _setTitle: function (v) {
+        this.left.setTitle(v);
+        this.right.setTitle(v);
+        this.label.setTitle(v);
+    },
+    _clearTitle: function () {
+        this.left.setTitle("");
+        this.right.setTitle("");
+        this.label.setTitle("");
+    },
+    setValue: function (date) {
+        date = date || {};
+        this.left.setValue(date.start);
+        this.right.setValue(date.end);
+    },
+    getValue: function () {
+        return {start: this.left.getValue(), end: this.right.getValue()};
+    }
+});
+BI.TimeInterval.EVENT_VALID = "EVENT_VALID";
+BI.TimeInterval.EVENT_ERROR = "EVENT_ERROR";
+BI.TimeInterval.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.time_interval", BI.TimeInterval);
\ No newline at end of file
diff --git a/src/widget/timesetting/timesetting.day.js b/src/widget/timesetting/timesetting.day.js
new file mode 100644
index 000000000..50a7125eb
--- /dev/null
+++ b/src/widget/timesetting/timesetting.day.js
@@ -0,0 +1,79 @@
+/**
+ * Created by Young's on 2016/4/22.
+ */
+BI.DayTimeSetting = BI.inherit(BI.Widget, {
+    _defaultConfig: function(){
+        return BI.extend(BI.DayTimeSetting.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-time-setting-day",
+            day: 1
+        })
+    },
+
+    _init: function(){
+        BI.DayTimeSetting.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var decrease = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "-",
+            height: 28,
+            width: 28
+        });
+        decrease.on(BI.Button.EVENT_CHANGE, function(){
+            var day = BI.parseInt(self.day.getValue());
+            if(day === 1) {
+                day = 31;
+            } else {
+                day --;
+            }
+            self.day.setValue(day);
+            self.fireEvent(BI.DayTimeSetting.EVENT_CHANGE);
+        });
+
+        var increase = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "+",
+            height: 28,
+            width: 28
+        });
+        increase.on(BI.Button.EVENT_CHANGE, function(){
+            var day = BI.parseInt(self.day.getValue());
+            if(day === 31) {
+                day = 1;
+            } else {
+                day ++;
+            }
+            self.day.setValue(day);
+            self.fireEvent(BI.DayTimeSetting.EVENT_CHANGE);
+        });
+
+        this.day = BI.createWidget({
+            type: "bi.label",
+            value: o.day,
+            height: 30,
+            width: 40
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [decrease, this.day, increase, {
+                type: "bi.label",
+                text: BI.i18nText("BI-Day_Ri"),
+                height: 30,
+                width: 20
+            }],
+            height: 30
+        })
+    },
+
+    getValue: function(){
+        return BI.parseInt(this.day.getValue());
+    },
+
+    setValue: function(v) {
+        this.day.setValue(v);
+    }
+});
+BI.DayTimeSetting.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.day_time_setting", BI.DayTimeSetting);
\ No newline at end of file
diff --git a/src/widget/timesetting/timesetting.hour.js b/src/widget/timesetting/timesetting.hour.js
new file mode 100644
index 000000000..c5eec3dd3
--- /dev/null
+++ b/src/widget/timesetting/timesetting.hour.js
@@ -0,0 +1,75 @@
+/**
+ * Created by Young's on 2016/4/22.
+ */
+BI.HourTimeSetting = BI.inherit(BI.Widget, {
+    _defaultConfig: function(){
+        return BI.extend(BI.HourTimeSetting.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-time-setting-hour",
+            hour: 0
+        })
+    },
+
+    _init: function(){
+        BI.HourTimeSetting.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        var decrease = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "-",
+            height: 28,
+            width: 28
+        });
+        decrease.on(BI.Button.EVENT_CHANGE, function(){
+            var hour = BI.parseInt(self.hour.getValue());
+            if(hour === 0) {
+                hour = 23;
+            } else {
+                hour --;
+            }
+            self.hour.setValue(hour);
+            self.fireEvent(BI.HourTimeSetting.EVENT_CHANGE);
+        });
+
+        var increase = BI.createWidget({
+            type: "bi.text_button",
+            cls: "operator-button",
+            text: "+",
+            height: 28,
+            width: 28
+        });
+        increase.on(BI.Button.EVENT_CHANGE, function(){
+            var hour = BI.parseInt(self.hour.getValue());
+            hour === 23 ? (hour = 0) : (hour ++);
+            self.hour.setValue(hour);
+            self.fireEvent(BI.HourTimeSetting.EVENT_CHANGE);
+        });
+
+        this.hour = BI.createWidget({
+            type: "bi.label",
+            value: o.hour,
+            height: 30,
+            width: 40
+        });
+        BI.createWidget({
+            type: "bi.left",
+            element: this,
+            items: [decrease, this.hour, increase, {
+                type: "bi.label",
+                text: BI.i18nText("BI-Hour_Dian"),
+                height: 30,
+                width: 20
+            }],
+            height: 30
+        })
+    },
+
+    getValue: function(){
+        return BI.parseInt(this.hour.getValue());
+    },
+
+    setValue: function(v) {
+        this.hour.setValue(v);
+    }
+});
+BI.HourTimeSetting.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.hour_time_setting", BI.HourTimeSetting);
\ No newline at end of file
diff --git a/src/widget/treelabel/treelabel.js b/src/widget/treelabel/treelabel.js
new file mode 100644
index 000000000..fa39f1f24
--- /dev/null
+++ b/src/widget/treelabel/treelabel.js
@@ -0,0 +1,51 @@
+BI.TreeLabel = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.TreeLabel.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-label",
+            itemsCreator: BI.emptyFn,
+            titles: [],
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.TreeLabel.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.titles = o.titles;
+        this.items = o.items;
+
+        this.view = BI.createWidget({
+            type: "bi.tree_label_view",
+            element: this,
+            titles: o.titles,
+            items: o.items
+        });
+        this.view.on(BI.TreeLabelView.EVENT_CHANGE, function (floors)  {
+            var op = {};
+            if (floors !== self.view.getMaxFloor() - 1) {
+                op.floors = floors;
+                op.selectedValues = self.getValue();
+                self._itemsCreator(op);
+            }
+            self.fireEvent(BI.TreeLabel.EVENT_CHANGE, arguments);
+        });
+    },
+
+    _itemsCreator: function (options) {
+        var self = this, o = this.options;
+        o.itemsCreator(options, function (data) {
+            self.populate(data);
+        })
+    },
+
+    populate: function (v) {
+        this.view.populate(v);
+    },
+
+    getValue: function () {
+        return this.view.getValue();
+    }
+});
+BI.TreeLabel.EVENT_CHANGE = "BI.TreeLabel.EVENT_CHANGE";
+$.shortcut('bi.tree_label', BI.TreeLabel);
\ No newline at end of file
diff --git a/src/widget/treelabel/treelabel.view.js b/src/widget/treelabel/treelabel.view.js
new file mode 100644
index 000000000..2d8bd8d22
--- /dev/null
+++ b/src/widget/treelabel/treelabel.view.js
@@ -0,0 +1,144 @@
+BI.TreeLabelView = BI.inherit(BI.Widget, {
+    _constant: {
+        LIST_LABEL_HEIGHT: 40,
+        DEFAULT_LEFT_GAP: 5
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.TreeLabelView.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-tree-label-view",
+            titleWidth: 60,
+            titles: [],
+            items: []
+        })
+    },
+
+    _init: function () {
+        BI.TreeLabelView.superclass._init.apply(this, arguments);
+        this.items = [];
+        this._initView();
+    },
+
+    _initView: function () {
+        var self = this, o = this.options;
+        this.title = BI.createWidget({
+            type: "bi.button_group",
+            height: this._constant.LIST_LABEL_HEIGHT * o.titles.length,
+            layouts: [{
+                type: "bi.vertical"
+            }]
+        });
+        this.right = BI.createWidget({
+            type: "bi.button_group",
+            cls: "list-label-group",
+            height: this._constant.LIST_LABEL_HEIGHT * this.items.length,
+            layouts: [{
+                type: "bi.horizontal"
+            }]
+        });
+        this._setTitles(o.titles);
+        this._setItems(o.items);
+        BI.createWidget({
+            type: "bi.absolute",
+            items: [{
+                el: this.title,
+                left: 0,
+                right: 0,
+                top: 0,
+                bottom: 0,
+                width: 60
+            }, {
+                el: this.right,
+                left: 65,
+                right: 0,
+                top: 0,
+                bottom: 0
+            }],
+            element: this
+        });
+    },
+
+    _setItems: function (items) {
+        var self = this;
+        var length = this.right.getAllButtons().length;
+        var deletes = [];
+        for (var i = 0; i < length; i++) {
+            deletes.push(i);
+        }
+        this.right.removeItemAt(deletes);
+        self.items = [];
+        BI.each(items, function (idx, values) {
+            var labelItems = [];
+            BI.each(values, function (idx, value) {
+                labelItems.push({
+                    title: value,
+                    text: value,
+                    value: value
+                })
+            });
+            var temp = BI.createWidget({
+                type: "bi.list_label",
+                items: labelItems,
+                showTitle: false
+            });
+            temp.on(BI.ListLabel.EVENT_CHANGE, function () {
+                self.fireEvent(BI.TreeLabelView.EVENT_CHANGE, idx);
+            });
+            self.items.push(temp);
+        });
+        var temp = BI.createWidget({
+            type: "bi.default",
+            items: self.items
+        });
+        this.right.addItems([temp]);
+        this.right.setHeight(self.items.length * this._constant.LIST_LABEL_HEIGHT);
+    },
+
+    _setTitles: function (titles) {
+        var length = this.title.getAllButtons().length;
+        var deletes = [], titleItems = [];
+        for (var i = 0; i < length; i++) {
+            deletes.push(i);
+        }
+        BI.each(titles, function (idx, title) {
+           titleItems.push({
+               text: title,
+               value: title,
+               title: title
+           });
+        });
+        this.title.removeItemAt(deletes);
+        this.title.addItems(BI.createItems(titleItems, {
+            type: "bi.label",
+            height: this._constant.LIST_LABEL_HEIGHT,
+            width: this.options.titleWidth
+        }));
+        this.title.setHeight(titles.length * this._constant.LIST_LABEL_HEIGHT);
+    },
+
+    _setValue: function (values) {
+        BI.each(this.items, function (idx, item) {
+            values[idx] && item.setValue(values[idx]);
+        })
+    },
+
+    populate: function(v) {
+        v.titles && this._setTitles(v.titles);
+        v.items && this._setItems(v.items);
+        v.values && this._setValue(v.values);
+    },
+
+    getMaxFloor: function () {
+        return this.items.length || 0;
+    },
+
+    getValue: function () {
+        var result = [];
+        BI.each(this.items, function (idx, item) {
+            result.push(item.getValue());
+        });
+        return result;
+    }
+});
+BI.TreeLabelView.EVENT_CHANGE = "BI.TreeLabelView.EVENT_CHANGE";
+$.shortcut('bi.tree_label_view', BI.TreeLabelView);
\ No newline at end of file
diff --git a/src/widget/uploadfile/progress.uploadfile.js b/src/widget/uploadfile/progress.uploadfile.js
new file mode 100644
index 000000000..8123ea6e7
--- /dev/null
+++ b/src/widget/uploadfile/progress.uploadfile.js
@@ -0,0 +1,111 @@
+/**
+ * Created by Young's on 2016/4/21.
+ */
+BI.UploadFileWithProgress = BI.inherit(BI.Widget, {
+
+    _constants: {
+        UPLOAD_PROGRESS: "__upload_progress__"
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.UploadFileWithProgress.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-upload-file-with-progress",
+            progressEL: BICst.BODY_ELEMENT,
+            multiple: false,
+            maxSize: 1024 * 1024,
+            accept: "",
+            url: ""
+        })
+    },
+
+    _init: function () {
+        BI.UploadFileWithProgress.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.file = BI.createWidget({
+            type: "bi.multifile_editor",
+            width: "100%",
+            height: "100%",
+            name: o.name,
+            url: o.url,
+            multiple: o.multiple,
+            accept: o.accept,
+            maxSize: o.maxSize
+        });
+
+        this.file.on(BI.MultifileEditor.EVENT_CHANGE, function () {
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_CHANGE, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADSTART, function () {
+            self.progressBar = BI.createWidget({
+                type: "bi.progress_bar",
+                width: 300
+            });
+            BI.createWidget({
+                type: "bi.center_adapt",
+                element: BI.Layers.create(self._constants.UPLOAD_PROGRESS, self.options.progressEL),
+                items: [self.progressBar],
+                width: "100%",
+                height: "100%"
+            });
+
+            BI.Layers.show(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_UPLOADSTART, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_ERROR, function () {
+            BI.Layers.remove(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_ERROR, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_PROGRESS, function (data) {
+            var process = Math.ceil(data.loaded / data.total * 100);
+            self.progressBar.setValue(process > 100 ? 100 : process);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_PROGRESS, arguments);
+        });
+        this.file.on(BI.MultifileEditor.EVENT_UPLOADED, function () {
+            BI.Layers.remove(self._constants.UPLOAD_PROGRESS);
+            self.fireEvent(BI.UploadFileWithProgress.EVENT_UPLOADED, arguments);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: {
+                    type: "bi.adaptive",
+                    scrollable: false,
+                    items: [this.file]
+                },
+                top: 0,
+                right: 0,
+                left: 0,
+                bottom: 0
+            }]
+        });
+    },
+
+    select: function () {
+        this.file.select();
+    },
+
+    getValue: function () {
+        return this.file.getValue();
+    },
+
+    upload: function () {
+        this.file.upload();
+    },
+
+    reset: function () {
+        this.file.reset();
+    },
+
+    setEnable: function (enable) {
+        BI.MultiFile.superclass.setEnable.apply(this, arguments);
+        this.file.setEnable(enable);
+    }
+});
+BI.UploadFileWithProgress.EVENT_CHANGE = "EVENT_CHANGE";
+BI.UploadFileWithProgress.EVENT_UPLOADSTART = "EVENT_UPLOADSTART";
+BI.UploadFileWithProgress.EVENT_ERROR = "EVENT_ERROR";
+BI.UploadFileWithProgress.EVENT_PROGRESS = "EVENT_PROGRESS";
+BI.UploadFileWithProgress.EVENT_UPLOADED = "EVENT_UPLOADED";
+$.shortcut("bi.upload_file_with_progress", BI.UploadFileWithProgress);
\ No newline at end of file
diff --git a/src/widget/web/web.js b/src/widget/web/web.js
new file mode 100644
index 000000000..bb7c84e3a
--- /dev/null
+++ b/src/widget/web/web.js
@@ -0,0 +1,154 @@
+/**
+ * web组件
+ * Created by GameJian on 2016/3/1.
+ */
+BI.WebPage = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.WebPage.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-web-page"
+        })
+    },
+
+    _init: function () {
+        BI.WebPage.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.iframe = BI.createWidget({
+            type: "bi.iframe"
+        });
+
+        this.label = BI.createWidget({
+            type: "bi.label",
+            cls: "web-page-text-button-label",
+            whiteSpace: "normal",
+            text: BI.i18nText("BI-Not_Add_Url")
+        });
+
+        this.del = BI.createWidget({
+            type: "bi.bubble_combo",
+            el: {
+                type: "bi.icon_button",
+                cls: "web-page-button img-shutdown-font",
+                title: BI.i18nText("BI-Basic_Delete"),
+                height: 24,
+                width: 24
+            },
+            popup: {
+                type: "bi.bubble_bar_popup_view",
+                buttons: [{
+                    value: BI.i18nText(BI.i18nText("BI-Basic_Sure")),
+                    handler: function () {
+                        self.fireEvent(BI.WebPage.EVENT_DESTROY)
+                    }
+                }, {
+                    value: BI.i18nText("BI-Basic_Cancel"),
+                    level: "ignore",
+                    handler: function () {
+                        self.del.hideView();
+                    }
+                }],
+                el: {
+                    type: "bi.vertical_adapt",
+                    items: [{
+                        type: "bi.label",
+                        text: BI.i18nText("BI-Sure_Delete_Current_Component"),
+                        cls: "web-page-delete-label",
+                        textAlign: "left",
+                        width: 300
+                    }],
+                    width: 300,
+                    height: 100,
+                    hgap: 20
+                },
+                maxHeight: 140,
+                minWidth: 340
+            },
+            invisible: true,
+            stopPropagation: true
+        });
+
+
+        this.href = BI.createWidget({
+            type: "bi.image_button_href",
+            cls: "web-page-button"
+        });
+
+        this.href.on(BI.ImageButtonHref.EVENT_CHANGE, function () {
+            var url = this.getValue();
+            self.setValue(this.getValue());
+            self._checkUrl(url);
+            self.fireEvent(BI.WebPage.EVENT_VALUE_CHANGE);
+        });
+
+        BI.createWidget({
+            type: "bi.absolute",
+            element: this,
+            items: [{
+                el: this.iframe
+            }, {
+                el: this.del,
+                right: 4,
+                top: 8
+            }, {
+                el: this.href,
+                right: 36,
+                top: 8
+            }, {
+                el: this.label,
+                top: 32,
+                left: 0,
+                bottom: 0,
+                right: 0
+            }]
+        });
+
+        this.setToolbarVisible(false);
+        this._showLabel();
+    },
+
+    _checkUrl: function(url){
+        BI.Bubbles.hide(this.getName());
+        if(BI.isEmptyString(url)){
+            BI.Bubbles.show(this.getName(), BI.i18nText("BI-Click_To_Add_Hyperlink"), this.href, {
+                offsetStyle: "left"
+            });
+        }
+    },
+
+    _hideLabel: function () {
+        this.label.invisible()
+    },
+
+    isSelected: function () {
+        return this.href.isSelected();
+    },
+
+    _showLabel: function () {
+        this.label.visible()
+    },
+
+    setToolbarVisible: function (v) {
+        this.href.setVisible(v);
+        this.del.setVisible(v);
+    },
+
+    getValue: function () {
+        return this.href.getValue()
+    },
+
+    setValue: function (url) {
+        var self = this;
+        if (BI.isNotEmptyString(url)) {
+            self._hideLabel();
+        } else {
+            this.setToolbarVisible(true);
+            this.href.showView();
+        }
+        this.href.setValue(url);
+        this.iframe.setSrc(BI.Func.formatAddress(url))
+    }
+});
+
+BI.WebPage.EVENT_DESTROY = "EVENT_DESTROY";
+BI.WebPage.EVENT_VALUE_CHANGE = "EVENT_VALUE_CHANGE";
+$.shortcut("bi.web_page", BI.WebPage);
\ No newline at end of file
diff --git a/src/widget/year/combo.year.js b/src/widget/year/combo.year.js
new file mode 100644
index 000000000..d1ec0e47b
--- /dev/null
+++ b/src/widget/year/combo.year.js
@@ -0,0 +1,96 @@
+/**
+ * 年份下拉框
+ *
+ * Created by GUY on 2015/8/28.
+ * @class BI.YearCombo
+ * @extends BI.Widget
+ */
+BI.YearCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-combo",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+        this.storeValue = "";
+        this.trigger = BI.createWidget({
+            type: "bi.year_trigger",
+            min: o.min,
+            max: o.max
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_FOCUS, function () {
+            self.storeValue = this.getKey();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_START, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_STOP, function () {
+            self.combo.showView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_ERROR, function () {
+            self.combo.isViewVisible() && self.combo.hideView();
+        });
+        this.trigger.on(BI.YearTrigger.EVENT_CONFIRM, function () {
+            if(self.combo.isViewVisible()) {
+                return;
+            }
+            if (this.getKey() && this.getKey() !== self.storeValue) {
+                self.setValue(this.getKey());
+            } else if (!this.getKey()) {
+                self.setValue();
+            }
+            self.fireEvent(BI.YearCombo.EVENT_CONFIRM);
+        });
+
+        this.popup = BI.createWidget({
+            type: "bi.year_popup",
+            min: o.min,
+            max: o.max
+        });
+
+        this.popup.on(BI.YearPopup.EVENT_CHANGE, function () {
+            self.setValue(self.popup.getValue());
+            self.combo.hideView();
+            self.fireEvent(BI.YearCombo.EVENT_CONFIRM);
+        });
+
+        this.combo = BI.createWidget({
+            type: "bi.combo",
+            element: this,
+            isNeedAdjustHeight: false,
+            isNeedAdjustWidth: false,
+            el: this.trigger,
+            popup: {
+                minWidth: 85,
+                stopPropagation: false,
+                el: this.popup
+            }
+        });
+        this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () {
+            var value = self.trigger.getKey();
+            if (BI.isNotNull(value)) {
+                self.popup.setValue(value);
+            } else if(!value && value !== self.storeValue){
+                self.popup.setValue(self.storeValue);
+            }else {
+                self.setValue();
+            }
+        });
+    },
+
+    setValue: function (v) {
+        this.trigger.setValue(v);
+        this.popup.setValue(v);
+    },
+
+    getValue: function () {
+        return this.popup.getValue();
+    }
+});
+BI.YearCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_combo', BI.YearCombo);
\ No newline at end of file
diff --git a/src/widget/year/popup.year.js b/src/widget/year/popup.year.js
new file mode 100644
index 000000000..ff3bb68a8
--- /dev/null
+++ b/src/widget/year/popup.year.js
@@ -0,0 +1,103 @@
+/**
+ * 年份展示面板
+ *
+ * Created by GUY on 2015/9/2.
+ * @class BI.YearPopup
+ * @extends BI.Trigger
+ */
+BI.YearPopup = BI.inherit(BI.Widget, {
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearPopup.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-popup",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31' //最大日期
+        });
+    },
+
+    _createYearCalendar: function (v) {
+        var o = this.options, y = this._year;
+
+        var calendar = BI.createWidget({
+            type: "bi.year_calendar",
+            min: o.min,
+            max: o.max,
+            logic: {
+                dynamic: true
+            },
+            year: y + v * 12
+        });
+        calendar.setValue(this._year);
+        return calendar;
+    },
+
+    _init: function () {
+        BI.YearPopup.superclass._init.apply(this, arguments);
+        var self = this;
+
+        this.selectedYear = this._year = new Date().getFullYear();
+
+        var backBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "pre-page-h-font",
+            width: 25,
+            height: 25,
+            value: -1
+        });
+
+        var preBtn = BI.createWidget({
+            type: "bi.icon_button",
+            cls: "next-page-h-font",
+            width: 25,
+            height: 25,
+            value: 1
+        });
+
+        this.navigation = BI.createWidget({
+            type: "bi.navigation",
+            element: this,
+            logic: {
+                dynamic: true
+            },
+            tab: {
+                cls: "year-popup-navigation",
+                height: 25,
+                items: [backBtn, preBtn]
+            },
+            cardCreator: BI.bind(this._createYearCalendar, this),
+
+            afterCardShow: function () {
+                this.setValue(self.selectedYear);
+                var calendar = this.getSelectedCard();
+                backBtn.setEnable(!calendar.isFrontYear());
+                preBtn.setEnable(!calendar.isFinalYear());
+            }
+        });
+
+        this.navigation.on(BI.Navigation.EVENT_CHANGE, function () {
+            self.selectedYear = this.getValue();
+            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
+            self.fireEvent(BI.YearPopup.EVENT_CHANGE, self.selectedYear);
+        });
+    },
+
+    getValue: function () {
+        return this.selectedYear;
+    },
+
+    setValue: function (v) {
+        var o = this.options;
+        if (Date.checkVoid(v, 1, 1, o.min, o.max)[0]) {
+            v = new Date().getFullYear();
+            this.selectedYear = "";
+            this.navigation.setSelect(BI.YearCalendar.getPageByYear(v));
+            this.navigation.setValue("");
+        } else {
+            this.selectedYear = v;
+            this.navigation.setSelect(BI.YearCalendar.getPageByYear(v));
+            this.navigation.setValue(v);
+        }
+    }
+});
+BI.YearPopup.EVENT_CHANGE = "EVENT_CHANGE";
+$.shortcut("bi.year_popup", BI.YearPopup);
\ No newline at end of file
diff --git a/src/widget/year/trigger.year.js b/src/widget/year/trigger.year.js
new file mode 100644
index 000000000..985a0410b
--- /dev/null
+++ b/src/widget/year/trigger.year.js
@@ -0,0 +1,106 @@
+/**
+ * 年份trigger
+ *
+ * Created by GUY on 2015/8/21.
+ * @class BI.YearTrigger
+ * @extends BI.Trigger
+ */
+BI.YearTrigger = BI.inherit(BI.Trigger, {
+    _const: {
+        hgap: 4,
+        vgap: 2,
+        triggerWidth: 25,
+        errorText: BI.i18nText("BI-Please_Input_Integer"),
+        errorTextInvalid: BI.i18nText("BI-Year_Trigger_Invalid_Text")
+    },
+
+    _defaultConfig: function () {
+        return BI.extend(BI.YearTrigger.superclass._defaultConfig.apply(this, arguments), {
+            extraCls: "bi-year-trigger",
+            min: '1900-01-01', //最小日期
+            max: '2099-12-31', //最大日期
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearTrigger.superclass._init.apply(this, arguments);
+        var self = this, o = this.options, c = this._const;
+        this.editor = BI.createWidget({
+            type: "bi.sign_editor",
+            height: o.height,
+            validationChecker: function (v) {
+                self.editor.setErrorText(!BI.isPositiveInteger(v) ? c.errorText : c.errorTextInvalid);
+                return v === "" || (BI.isPositiveInteger(v) && !Date.checkVoid(v, 1, 1, o.min, o.max)[0]);
+            },
+            quitChecker: function (v) {
+                return false;
+            },
+            hgap: c.hgap,
+            vgap: c.vgap,
+            allowBlank: true,
+            errorText: c.errorText
+        })
+        this.editor.on(BI.SignEditor.EVENT_FOCUS, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_FOCUS);
+        });
+        this.editor.on(BI.SignEditor.EVENT_STOP, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_STOP);
+        });
+        this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () {
+            var value = self.editor.getValue();
+            if (BI.isNotNull(value)) {
+                self.editor.setValue(value);
+                self.editor.setTitle(value);
+            }
+            self.fireEvent(BI.YearTrigger.EVENT_CONFIRM);
+        })
+        this.editor.on(BI.SignEditor.EVENT_SPACE, function () {
+            if (self.editor.isValid()) {
+                self.editor.blur();
+            }
+        });
+        this.editor.on(BI.SignEditor.EVENT_START, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_START);
+        });
+        this.editor.on(BI.SignEditor.EVENT_ERROR, function () {
+            self.fireEvent(BI.YearTrigger.EVENT_ERROR);
+        });
+        BI.createWidget({
+            element: this,
+            type: 'bi.htape',
+            items: [
+                {
+                    el: this.editor
+                }, {
+                    el: {
+                        type: "bi.text_button",
+                        baseCls: "bi-trigger-year-text",
+                        text: BI.i18nText("BI-Multi_Date_Year"),
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }, {
+                    el: {
+                        type: "bi.trigger_icon_button",
+                        width: c.triggerWidth
+                    },
+                    width: c.triggerWidth
+                }
+            ]
+        });
+    },
+    setValue: function (v) {
+        this.editor.setState(v);
+        this.editor.setValue(v);
+        this.editor.setTitle(v);
+    },
+    getKey: function () {
+        return this.editor.getValue() | 0;
+    }
+});
+BI.YearTrigger.EVENT_FOCUS = "EVENT_FOCUS";
+BI.YearTrigger.EVENT_ERROR = "EVENT_ERROR";
+BI.YearTrigger.EVENT_START = "EVENT_START";
+BI.YearTrigger.EVENT_CONFIRM = "EVENT_CONFIRM";
+BI.YearTrigger.EVENT_STOP = "EVENT_STOP";
+$.shortcut("bi.year_trigger", BI.YearTrigger);
\ No newline at end of file
diff --git a/src/widget/yearmonth/combo.yearmonth.js b/src/widget/yearmonth/combo.yearmonth.js
new file mode 100644
index 000000000..ee6fc2b51
--- /dev/null
+++ b/src/widget/yearmonth/combo.yearmonth.js
@@ -0,0 +1,57 @@
+/**
+ * 年份 + 月份下拉框
+ *
+ * @class BI.YearMonthCombo
+ * @extends BI.Widget
+ */
+BI.YearMonthCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearMonthCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-month-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearMonthCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.year = BI.createWidget({
+            type: "bi.year_combo"
+        });
+
+        this.month = BI.createWidget({
+            type: "bi.month_combo"
+        });
+
+        this.year.on(BI.YearCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM);
+        });
+
+        this.month.on(BI.MonthCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM);
+        });
+
+        BI.createWidget({
+            type: "bi.center",
+            element: this,
+            hgap: 5,
+            items: [this.year, this.month]
+        });
+
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.month.setValue(v.month);
+        this.year.setValue(v.year);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            month: this.month.getValue()
+        };
+    }
+});
+BI.YearMonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_month_combo', BI.YearMonthCombo);
\ No newline at end of file
diff --git a/src/widget/yearquarter/combo.yearquarter.js b/src/widget/yearquarter/combo.yearquarter.js
new file mode 100644
index 000000000..19633f44d
--- /dev/null
+++ b/src/widget/yearquarter/combo.yearquarter.js
@@ -0,0 +1,57 @@
+/**
+ * 年份 + 月份下拉框
+ *
+ * @class BI.YearQuarterCombo
+ * @extends BI.Widget
+ */
+BI.YearQuarterCombo = BI.inherit(BI.Widget, {
+    _defaultConfig: function () {
+        return BI.extend(BI.YearQuarterCombo.superclass._defaultConfig.apply(this, arguments), {
+            baseCls: "bi-year-quarter-combo",
+            height: 25
+        });
+    },
+    _init: function () {
+        BI.YearQuarterCombo.superclass._init.apply(this, arguments);
+        var self = this, o = this.options;
+
+        this.year = BI.createWidget({
+            type: "bi.year_combo"
+        });
+
+        this.quarter = BI.createWidget({
+            type: "bi.quarter_combo"
+        });
+
+        this.year.on(BI.YearCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM);
+        });
+
+        this.quarter.on(BI.QuarterCombo.EVENT_CONFIRM, function(){
+            self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM);
+        });
+
+        BI.createWidget({
+            type: "bi.center",
+            element: this,
+            hgap: 5,
+            items: [this.year, this.quarter]
+        });
+
+    },
+
+    setValue: function (v) {
+        v = v || {};
+        this.quarter.setValue(v.quarter);
+        this.year.setValue(v.year);
+    },
+
+    getValue: function () {
+        return {
+            year: this.year.getValue(),
+            quarter: this.quarter.getValue()
+        };
+    }
+});
+BI.YearQuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM";
+$.shortcut('bi.year_quarter_combo', BI.YearQuarterCombo);
\ No newline at end of file